Documentación
Wiki
Cómo se usa BogaBot y cómo levantar tu propia instancia en tu server. El bot es de uso libre: clonás el repo y lo corrés con tu propio bot y tus propios tokens.
Qué es
BogaBot es un bot de Discord modular para un grupo de amigos. El módulo central es el ranking de League of Legends: vincular cuenta de Riot → ingerir partidas desde la Riot API → calcular un puntaje configurable por jugador → publicar rankings en Discord. Alrededor de eso hay un detector de trolls que juzga cada partida, avisos en vivo, sonidos en los canales de voz y un sistema de puntos canjeables.
Está armado por capas reemplazables: el storage vive detrás de una interfaz (hoy es “Discord como base de datos”; migrar a SQLite o Postgres es una clase nueva), cada módulo es un cog autocontenido y tanto la fórmula del ranking como el detector de trolls son archivos YAML editables sin tocar código.
Para jugadores
Si el bot ya está en tu server, lo único que tenés que hacer es vincularte:
- Corré
/link Nombre#TAGcon tu Riot ID completo (el nombre y el tag que ves en el cliente de LoL, ej.Faker#KR1). - El bot valida la cuenta contra la Riot API. Si existe, queda vinculada y tus partidas de esta semana empiezan a contar.
- Usá
/rankingcuando quieras ver la tabla, o esperá el posteo automático de cada noche.
Además
/trollsmuestra quién viene trolleando más;/troll-analizarte dice por qué tu última partida sumó (o no) puntos troll./sonidohace que el bot entre a tu canal de voz y tire un audio.- Si tenés el rol de puntos, sumás estando en voz con amigos y jugando LoL. Mirá cuántos tenés con
/puntosy canjealos por un sonido propio con/canjear-sonido. - Si el server configuró un canal de comandos, usalos ahí. Los que tienen 🔒 en
/helpte responden solo a vos.
Requisitos
Runtime | Python 3.12+ · discord.py[voice] · aiohttp |
|---|---|
ffmpeg | En el PATH, para reproducir y medir los sonidos (sin él, todo lo demás anda) |
Cuenta de Discord | Con permiso para crear una Application y un bot |
Riot API key | Personal API Key (no vence) o Development (vence cada 24 h) |
Server de Discord | Donde invitás el bot, con canales y roles propios |
Hosting | Local (python run.py) o un server Linux con systemd |
Setup en Windows / PowerShell: python -m venv venv → venv\Scripts\activate → pip install -r requirements.txt. En Linux: sudo apt install ffmpeg para los sonidos.
Crear el bot en Discord
Paso 1
Crear el bot en Discord
En el Developer Portal: New Application → pestaña Bot → Reset Token. Ese valor va en DISCORD_TOKEN. Dejá los Privileged Gateway Intents apagados, el bot no los necesita.
Paso 2
Invitarlo a tu server
OAuth2 → URL Generator. Scopes: bot y applications.commands. Permisos: View Channel, Send Messages, Read Message History y Embed Links; Connect y Speak para los sonidos; Manage Roles solo si vas a usar LOL_ROLE_ID.
Paso 3
Activar el modo desarrollador
Ajustes de usuario → Avanzado → Modo de desarrollador. Con eso, click derecho sobre cualquier canal, rol o server te deja copiar su ID.
Paso 4
Crear canales y roles
Como mínimo un canal privado de storage, uno público de rankings, el general y un rol de administración. El resto es opcional (ver la tabla completa en la wiki).
Paso 5
Conseguir la Riot API key
En developer.riotgames.com → Register Product → Personal API Key: gratis y no vence (Riot la aprueba a mano). Mientras tanto sirve la Development Key, que vence cada 24 h y se renueva con /riot-key sin reiniciar.
Paso 6
Completar el .env y correr
Con todos los IDs y tokens, completás .env.staging (o .env.production) y corrés python run.py. En el primer arranque registra los slash commands. Para los sonidos, ffmpeg tiene que estar instalado.
Permisos al invitarlo
En OAuth2 → URL Generator, scopes bot y applications.commands. Bot permissions:
- View Channel, Send Messages, Read Message History y Embed Links en los canales de storage, rankings, general, trolls y avisos.
- Connect y Speak para los sonidos en los canales de voz.
- Manage Roles solo si vas a usar
LOL_ROLE_ID(para que el bot asigne ese rol al vincular). - No requiere intents privilegiados: dejalos apagados.
Canales y roles
Con el modo desarrollador activado (Ajustes → Avanzado), click derecho sobre cada canal o rol te deja copiar su ID. Necesitás también el ID del server para DISCORD_GUILD_ID.
| Creá esto | Tipo | Variable | Para qué |
|---|---|---|---|
| Canal de texto privado (solo lo ve el bot) | canal | STORAGE_CHANNEL_ID | El bot lo usa como base de datos: guarda mensajes JSON acá. Nadie más debería verlo ni escribir en él. |
| Canal público para los rankings | canal | RANKING_CHANNEL_ID | Ranking diario, recap semanal "Trolls y Pros" y, si no hay canal de trolls, las alertas troll. |
| Canal general del server | canal | GENERAL_CHANNEL_ID | Solo le llega una línea corta por cada papelón histórico (15+ puntos troll). Nada más. |
| Canal de alertas troll · opcional | canal | TROLL_CHANNEL_ID | Trolleadas con su anécdota y el detalle, y el ranking troll diario. Si falta, va al de rankings. |
| Canal de avisos de partida terminada · opcional | canal | MATCH_NOTIFY_CHANNEL_ID | Aviso en vivo por cada partida del grupo: los 10 jugadores y el troll-o-metro. |
| Canal de comandos del bot · opcional | canal | BOT_CHANNEL_ID | Si lo seteás, los miembros comunes solo pueden usar comandos ahí (o en el de admin). Los devs, en cualquier lado. |
| Canal para comandos de admin · opcional | canal | ADMIN_CHANNEL_ID | Los comandos de administración solo se pueden correr ahí, y ahí llegan los avisos de vencimiento de la Riot key. |
| Canal de logs del bot · opcional | canal | LOG_CHANNEL_ID | El bot reenvía acá sus logs WARNING+ (Riot caído, key vencida, etc.) además de la consola. |
| Rol de quien administra el bot | rol | DEV_ROLE_ID | Habilita los comandos de administración, de sonidos y de puntos marcados como dev. |
| Rol de jugador / miembro del grupo · opcional | rol | PLAYER_ROLE_ID | Solo afecta qué secciones muestran /help y /ayuda. |
| Rol que junta puntos ("Boguero") · opcional | rol | POINTS_ROLE_ID | Quien lo tiene gana puntos en voz y jugando, y puede canjearlos. Sin este rol, el módulo de puntos no se carga. |
| Rol que se asigna solo al vincularse · opcional | rol | LOL_ROLE_ID | Al hacer /link, el bot te da este rol (necesita permiso Manage Roles). |
STORAGE_CHANNEL_ID es la base de datos del bot (mensajes JSON). No debería verlo ni escribir en él nadie más que el bot.Riot API key
En developer.riotgames.com generás la key. Va en RIOT_API_KEY.
| Tipo de key | Duración | Cuándo |
|---|---|---|
| Personal API Key | No vence. Se pide en Register Product; Riot la aprueba a mano (puede tardar unos días) | El bot corriendo en serio. Poné RIOT_KEY_TTL_HOURS=0 |
| Development | Vence cada 24 h | Para probar mientras llega la otra. Se renueva con /riot-key |
/riot-key <key> (rol dev, en el canal de admin) valida la key nueva contra Riot, la aplica sin reiniciar y la guarda en RIOT_KEY_FILE para que sobreviva reinicios. Sin argumento, muestra cuándo vence la actual. Con RIOT_KEY_TTL_HOURS mayor a 0, el bot avisa en el canal de admin (etiquetando al rol dev) RIOT_KEY_WARN_MINUTES antes de que venza y cuando vence.
Ajustá también RIOT_PLATFORM y RIOT_REGION a tu región. Por defecto está en LAS: RIOT_PLATFORM=la2, RIOT_REGION=americas (LAS, LAN y NA rutean a americas).
CRITICAL (con cooldown de 3 h) que llega al canal de logs. Si cambiás a una key de otra app de Riot, los puuid cambian (vienen encriptados por app): el bot los re-resuelve solo por Riot ID.Variables de entorno
Todo sale de un archivo .env — el código nunca hardcodea secretos ni IDs, y si falta una variable requerida el bot no arranca y dice cuál. Ninguno de los .env.* reales se commitea.
Discord: token, canales y roles
| Variable | Descripción |
|---|---|
DISCORD_TOKEN | Token del bot (pestaña Bot → Reset Token). Discord no lo vuelve a mostrar. |
DISCORD_GUILD_ID | ID del server. Opcional, pero registra los slash commands al instante. |
STORAGE_CHANNEL_ID | Canal privado que el bot usa como base de datos. |
RANKING_CHANNEL_ID | Canal donde publica los rankings. |
GENERAL_CHANNEL_ID | Canal general: ahí van solo los papelones históricos. |
TROLL_CHANNEL_ID | Canal de alertas y ranking troll (opcional; default RANKING_CHANNEL_ID). |
MATCH_NOTIFY_CHANNEL_ID | Canal de avisos de partida terminada (opcional). |
MATCH_POLL_INTERVAL_MINUTES | Cada cuántos minutos se chequean partidas nuevas, para los avisos y las alertas troll (default 5). |
BOT_CHANNEL_ID | Canal donde los miembros comunes pueden usar comandos (opcional). |
ADMIN_CHANNEL_ID | Canal donde se corren los comandos de administración (opcional). |
DEV_ROLE_ID | Rol habilitado para los comandos de administración. |
PLAYER_ROLE_ID | Rol de jugador; define qué ven /help y /ayuda. |
LOL_ROLE_ID | Rol que el bot asigna al vincular una cuenta (opcional). |
Riot API
| Variable | Descripción |
|---|---|
RIOT_API_KEY | API key de Riot. En producción, la Personal API Key (no vence). Se rota en caliente con /riot-key. |
RIOT_PLATFORM | Plataforma de la región (LAS → la2). |
RIOT_REGION | Routing regional (LAS/LAN/NA → americas). |
RIOT_KEY_FILE | Dónde se guarda la key cargada con /riot-key (default data/riot_key.json, permisos 600). |
RIOT_KEY_TTL_HOURS | Horas de vida de la key para el recordatorio (default 24, la dev key). Con la Personal API Key: 0 = no vence. |
RIOT_KEY_WARN_MINUTES | Cuántos minutos antes de vencer se avisa en el canal de admin (default 120). |
Horarios
| Variable | Descripción |
|---|---|
TIMEZONE | Zona horaria para los cortes de día/semana (default America/Argentina/Buenos_Aires). |
DAILY_POST_HOUR / DAILY_POST_MINUTE | Hora local del job diario (default 10:00). Recomendado 23:55, para que el ranking de hoy no salga vacío. |
Archivos de configuración y estado
| Variable | Descripción |
|---|---|
SCORING_CONFIG_PATH | Fórmula del ranking (default config/scoring.yaml). |
TROLLS_CONFIG_PATH | Umbrales y puntos del detector de trolls (default config/trolls.yaml). |
TROLLS_STATE_FILE | Desde cuándo cuenta el ranking troll; lo escribe /trolls-reiniciar (default data/trolls_state.json). |
Logs
| Variable | Descripción |
|---|---|
LOG_LEVEL | Nivel de log de la consola (default INFO). |
LOG_CHANNEL_ID | Canal donde el bot manda sus propios logs (opcional). |
LOG_CHANNEL_LEVEL | Nivel mínimo que se reenvía a ese canal (default WARNING). |
Sonidos
| Variable | Descripción |
|---|---|
SOUNDS_ENABLED | Sonidos al azar en los canales de voz (default true). /sonido anda igual aunque esté apagado. |
SOUNDS_DIR | Carpeta de los audios, fuera de git (default sounds/). |
SOUNDS_CHANCE | Probabilidad de que suene uno en cada chequeo, de 0 a 1 (default 0.15). |
SOUNDS_CHECK_INTERVAL_MINUTES | Cada cuánto se tira el dado (default 5). |
SOUNDS_COOLDOWN_MINUTES | Mínimo entre dos sonidos al azar (default 45). |
SOUNDS_ACTIVE_FROM / SOUNDS_ACTIVE_TO | Horario en que suenan (0-23; puede cruzar la medianoche). 0 y 0 = todo el día. |
Puntos y canjes
| Variable | Descripción |
|---|---|
POINTS_ROLE_ID | Rol que junta y canjea puntos. Sin él, el módulo de puntos no se carga. |
POINTS_FILE | Dónde se guardan los puntos (default data/points.json). |
POINTS_VOICE_INTERVAL_MINUTES / POINTS_VOICE_AMOUNT | Puntos por estar en voz: cuántos y cada cuánto (default 1 cada 5 min). |
POINTS_VOICE_DAILY_CAP | Tope diario de puntos por voz (default 60). |
POINTS_LOL_GAME / POINTS_LOL_WIN | Puntos por partida de LoL guardada y extra si la ganaste (default 5 y 5). |
SOUND_REDEEM_COST | Lo que cuesta canjear un sonido (default 100). |
SOUND_REDEEM_DAYS | Días que dura un sonido canjeado (default 7). |
SOUND_REDEEM_MAX_SECONDS | Duración máxima del audio canjeado (default 8 s). |
SOUND_REDEEM_MAX_ACTIVE | Sonidos canjeados activos por persona (default 1). |
Staging vs. producción
El ambiente lo elige la variable de shell BOGABOT_ENV (se setea en la terminal antes de correr, *no* dentro del .env):
| BOGABOT_ENV | Carga | Uso |
|---|---|---|
sin setear o staging | .env.staging | Default. Desarrollo y pruebas. |
production | .env.production | El bot real, en el server real. |
# local, default staging python run.py # explícito $env:BOGABOT_ENV = "production" python run.py # con el script (consola + log en logs\) .\scripts\run_bot.ps1 -Environment production
El default es staging a propósito: si te olvidás de setear la variable, nunca corrés contra producción por accidente. Recomendado: staging apunta a otro bot y otro server, no al mismo, porque el storage vive en canales de Discord y mezclarías datos de prueba con datos reales.
Comandos
Si hay BOT_CHANNEL_ID, los miembros comunes solo pueden usar comandos en ese canal (o en el de admin); los devs, en cualquier lado. Los comandos de administración (/link-admin, /unlink-admin, /ingest-now, /riot-key, /trolls-reiniciar, /trolls-recalcular) además exigen el canal de admin.
🎮 Ranking LoL
| Comando | Qué hace | Quién |
|---|---|---|
/link <Nombre#TAG> | Vincula tu cuenta de Riot con tu Discord. Se valida contra la Riot API; si el Riot ID no existe, no guarda nada. | todos |
/unlink | Desvincula tu cuenta. Tus partidas dejan de contar para el ranking. | todos |
/ranking [Hoy | Semana] | Muestra el ranking del grupo on-demand, sin esperar al posteo automático. Solo cuentan partidas Ranked (Flex y Solo/Duo). | todos |
/link-admin <usuario> <Nombre#TAG> | Vincula la cuenta de Riot de otro usuario del server. | rol dev |
/unlink-admin <usuario> | Desvincula la cuenta de otro usuario del server. | rol dev |
/ingest-now | Fuerza una ingesta de partidas. Es idempotente: el dedup por (match_id, discord_id) saltea lo que ya está guardado. | rol dev |
/riot-key [key] | Carga una RIOT_API_KEY nueva sin reiniciar el bot (la valida y la guarda). Sin key, muestra cuándo vence la actual. La respuesta es efímera: la key no queda visible. | rol dev |
🤡 Trolls
| Comando | Qué hace | Quién |
|---|---|---|
/trolls [Semana | Semana pasada | Mes | Histórico] | Ranking troll por índice (puntos troll promedio por partida): categoría, especialidad, peor partida y tendencia contra el período anterior. | todos |
/troll-analizar [usuario] [partida] | Juzga una partida (por defecto la última guardada): qué cargos troll tiene, cuántos puntos suma cada uno y por qué. | todos |
/trolls-reglas | Qué detecta el bot y cuántos puntos suma cada cosa, con la config que está activa. | todos |
/trolls-reiniciar | El ranking troll arranca de cero desde ahora. Las partidas viejas quedan guardadas. | rol dev |
/trolls-recalcular | Vuelve a pedirle a Riot las partidas guardadas con un análisis viejo para completarles stats y timeline. Corre solo al arrancar; esto lo fuerza a mano, en silencio. | rol dev |
🔊 Sonidos
| Comando | Qué hace | Quién |
|---|---|---|
/sonido [nombre] | El bot entra a tu canal de voz, tira el sonido (o uno al azar) y se va. | todos |
/sonidos | Lista los sonidos cargados. | todos |
/canjear-sonido <nombre> <audio> | Cambiás puntos por subir un sonido tuyo temporal (por defecto 100 puntos, hasta 8 s, dura 7 días). | rol puntos |
/sonido-del <nombre> | Borra un sonido. El dueño puede borrar el que canjeó; un dev, cualquiera. | rol puntos |
/sonido-add <nombre> <audio> | Sube un sonido permanente (mp3, ogg o wav, hasta 2 MB). | rol dev |
/sonido-forzar [nombre] [canal] | El bot entra a un canal de voz y tira ese sonido. Si hay otro sonando, espera su turno. | rol dev |
💰 Puntos
| Comando | Qué hace | Quién |
|---|---|---|
/puntos [usuario] | Cuántos puntos tenés (o los de otro) y cómo se ganan. | todos |
/puntos-top | Ranking de puntos del server. | todos |
/puntos-dar <usuario> <cantidad> | Suma o resta puntos a alguien (cantidad negativa para restar). | rol dev |
ℹ️ Ayuda
| Comando | Qué hace | Quién |
|---|---|---|
/help · /ayuda | Listan los comandos que podés usar según tus roles. Son dos nombres para lo mismo y la respuesta la ves solo vos. | todos |
Cómo se calcula el ranking
- Cada partida se guarda como un registro por jugador, pero solo si la jugaste acompañado de al menos otro vinculado del grupo. Las solitarias se descartan en la ingesta (se chequea
metadata.participantsdel JSON de match-v5). - Se excluyen los remakes (menos de 5 min o early surrender).
- El ranking diario y el semanal cuentan solo Ranked (Solo/Duo y Flex). Normales, ARAM y rotativos se guardan igual (sirven para el detector de trolls y los puntos), pero no suman al ranking.
- Las ventanas son día y semana desde el lunes 00:00 hora local (
TIMEZONE, default Buenos Aires). - En cada ventana se agregan las stats por jugador y el motor de scoring aplica la fórmula de
config/scoring.yaml. - El job diario corre a
DAILY_POST_HOUR:DAILY_POST_MINUTE(recomendado 23:55): ingesta → ranking del día → si hubo trolleadas, cómo va el ranking troll de la semana. Los lunes, además, el recap semanal “Trolls y Pros” de la semana que cerró — contando solo Ranked Flex (queue 440), para medir el juego serio del grupo — y la corona del Troll de la semana. - Dedup por
(match_id, discord_id)sin cursor: cada corrida pide “desde el lunes” (con un día de margen, por las partidas que cruzan la medianoche) y saltea lo ya guardado.
Motor de scoring
La fórmula vive en config/scoring.yaml y se edita sin tocar código. Para cada jugador se calcula cada métrica (promediada por partida), se normaliza entre todos los jugadores y el puntaje final es la suma de peso × valor_normalizado.
aggregation | per_game_average — promedio por partida — calidad sobre cantidad: jugar muchas partidas mediocres no te sube |
|---|---|
normalization | zscore — (valor − promedio) / desvío, para que ninguna métrica domine por tener números más grandes |
normalization acepta zscore (recomendado), minmax (escala 0..1 entre el peor y el mejor) o none (valor crudo; los pesos se calibran a mano).
Métricas activas por defecto
| Métrica | Peso | Qué mide |
|---|---|---|
carry_rate | 5.0 | % de partidas carreadas (victoria + KDA ≥ 5) |
troll_rate | 4.0 ↓ | % de partidas troleadas (KDA < 0.5) |
kda | 3.0 | (kills + assists) / muertes |
win_rate | 2.0 | % de victorias |
avg_deaths | 1.5 ↓ | muertes promedio por partida |
damage_per_min | 1.0 | daño a campeones por minuto |
avg_vision | 0.5 | vision score promedio |
↓ = menos es mejor (el valor normalizado se invierte). Una partida es carreada si la ganaste con KDA ≥ 5 y troleada si terminaste con KDA < 0,5. El motor soporta además estas métricas, desactivadas por defecto — se activan agregándolas al YAML: avg_kills, avg_assists, cs_per_min, games_played.
Detector de trolls
Después de cada partida, cada jugador del grupo se juzga con las reglas de abajo. Las que dicen timeline usan una consulta más a Riot (qué pasó y cuándo); el resto sale de las stats de la partida. Todo se ajusta en config/trolls.yaml sin tocar código (reiniciando el bot), y como el ranking troll se calcula al vuelo, un cambio ahí recalcula también el historial.
Cómo se suman los puntos
- Cada regla que se cumple es un cargo con sus puntos troll.
- En ranked (Solo/Duo o Flex) los puntos se multiplican por ×1,25; si igual ganaron, por ×0,5 (lo llevaron de mochila).
- Los cargos menores (🔸 en la tabla: mal rendimiento, poca KP, poco daño, línea perdida, visión, farm, primera sangre, FF…) suman entre todos como mucho 4. Para ser trolleada hace falta una señal fuerte: AFK, 0 kills y 0 asistencias, items vendidos, dejar caer la base, feeder, throw o ancla del equipo.
- Los umbrales cambian según el modo: ARAM y los modos caóticos (URF, One for All…) toleran más muertes, y las reglas de línea y de base son solo de la Grieta.
- Reglas que miden lo mismo no se suman: feeder reemplaza a KDA de la vergüenza y a tiempo muerto; ciego reemplaza a sin control wards.
Qué pasa según los puntos de la partida
| Puntos | Qué pasa |
|---|---|
| menos de 8 | Nada aparte: suma al ranking troll y se ve en el troll-o-metro del aviso de partida. |
| 8 o más | 🤡 Trolleada: en TROLL_CHANNEL_ID (o el de rankings), una línea con la anécdota etiquetando al jugador, más el detalle compacto. |
| 15 o más | 💀 Papelón: además, una línea corta en `GENERAL_CHANNEL_ID`. Es lo único que llega a #general. |
Solo se avisan partidas de las últimas 36 h (alert_max_age_hours): si el bot estuvo caído o alguien se acaba de vincular, lo viejo no se anuncia.
Ranking troll (/trolls)
Ordena por índice troll — puntos por partida —, no por el total, así que jugar más no suma: el que la trollea fuerte en 2 partidas queda arriba del que jugó 18 y trolleó 2. Para que una partida suelta no decida por azar, cada jugador arranca con 2 partidas “fantasma” que valen el promedio del grupo (index.prior_games) y una sola partida cuenta como mucho 30 puntos (index.max_game_points). Muestra la categoría, el % de partidas trolleadas y la tendencia contra el período anterior (📈 / 📉 / ➡️ / 🆕). /trolls-reiniciar lo pone en cero desde ese momento.
Categorías (según el índice)
Las reglas
| Regla | Pts | Cuándo |
|---|---|---|
| 💤 AFK timeline | 8 | Minutos seguidos quieto, vivo y sin ganar experiencia. |
| 👻 ¿Estaba AFK? | 5 | 0 kills y 0 asistencias en una partida donde su equipo sí mató. |
| 💸 Liquidación total timeline | 5 | Vendió 6 items o más en la partida (inteo). |
| 🏚️ Nos tiraban la base timeline | 5 | Cayeron inhibidores o torres del nexo mientras estaba vivo y lejos, sin estar haciendo split push. +3 si estaba farmeando. |
| 🍽️ Feeder profesional | 3 | Muertes según lo que duró la partida (≈3,3 cada 10 min, mínimo 8) con KDA < 1. Suma extra por cada 2 muertes de más. |
| 💥 Throw timeline | 3 | Lo agarraron solo, sin pelea alrededor, y en menos de un minuto perdieron Barón, Ancestral o el nexo. |
| ⚓ Ancla del equipo | 2 | Murió más que los otros cuatro de su equipo juntos (con al menos 7 muertes). |
| 📉 KDA de la vergüenza | 2 | KDA menor a 0,5 con al menos 5 muertes (no se suma si ya es feeder). |
| ⚰️ Veraneando en la fuente | 2 | Pasó muerto un cuarto de la partida o más. |
| ⏰ Speedrun de muertes timeline | 2 | 3 muertes o más antes del minuto 10. |
| 🚜 Le pasaron el trapo en línea timeline | 2 | 2.500 de oro abajo contra su rival de línea al minuto 15 (1.500 si es support). |
| 🎁 Delivery a domicilio timeline | 2 | 4 muertes o más contra su rival de línea, y que sean buena parte (40%+) de todas sus muertes. |
| 🪶 Daño de cotillón | 2 | Menos del 10% del daño de su equipo, salvo que haya tanqueado. |
| 🏝️ Jugando otra partida | 2 | Participó en menos del 20% de las kills de su equipo. |
| 🩸 Regaló la primera sangre timeline | 1 | Primera muerte de la partida antes del minuto 5 (+1 antes del 3). |
| 🕊️ Pacifista | 1 | 0 kills en 20 minutos o más, con poco daño (no aplica a supports). |
| 🙈 Ciego voluntario | 1 | Vision score por minuto muy bajo (a los supports se les exige más). |
| 🧿 Ni un control ward | 1 | Cero control wards en 25 minutos, y además visión floja. |
| 🌾 Alérgico al farm | 1 | Farm por minuto bajo para su rol, salvo que carree con daño. |
| 🤖 Ejecutado timeline | 1 | 2 muertes o más por torres, minions o monstruos. |
| 💰 Ahorrista timeline | 1 | Murió con más de 3.000 de oro encima, antes del minuto 25. |
| 🏳️ FF al 15 | 2 | Derrota por rendición antes del 20. Agravante: solo suma si ya tiene un cargo propio. |
| 🧹 Barrida histórica | 1 | Derrota por 20 kills o más de diferencia. Agravante, como el FF. |
| ❓ Tóxico del '?' | 1 | 15 pings de "?" o más. |
| 🥄 Cuchara de madera | 2 | Último puesto en Arena. |
/trolls-recalcular fuerza lo mismo a mano.Avisos en vivo y logs
Partida terminada
Si MATCH_NOTIFY_CHANNEL_ID está seteado, cada MATCH_POLL_INTERVAL_MINUTES (5 por defecto) el bot chequea partidas nuevas y, por cada una que cuente, postea un cuadro con las 10 posiciones, etiquetando a los jugadores del grupo que la jugaron (con el resultado de cada uno, por si quedaron en equipos contrarios) y un troll-o-metro con los puntos troll de cada uno.
Los avisos salen de cualquier ingesta — el chequeo periódico, el job diario o /ingest-now — y una sola vez por partida: la ingesta tiene un lock y el dedup hace que correr todo junto no duplique nada.
Logs a Discord
Si LOG_CHANNEL_ID está seteado, los logs de nivel LOG_CHANNEL_LEVEL (WARNING por defecto) o superior se reenvían también a ese canal, además de la consola. Pensado para enterarte de errores (Riot caído, key vencida) sin mirar la terminal. Los errores de red contra Riot se reintentan con backoff antes de avisar.
Sonidos
El bot entra a un canal de voz, tira un audio corto y se va. Una sola reproducción a la vez en todo el bot, y cualquier audio se corta a los 20 s por las dudas. Necesita ffmpeg instalado y los permisos Connect y Speak.
Tres formas de que suene
- A pedido:
/sonido [nombre]en tu canal de voz (vacío = uno al azar). - Forzado (dev):
/sonido-forzar [nombre] [canal]— en el canal que elijas, en el tuyo o en uno con gente al azar. Si hay otro sonando, espera su turno. - Al azar: cada
SOUNDS_CHECK_INTERVAL_MINUTES(5) el bot tira un dado conSOUNDS_CHANCE(15%). Si sale, dentro del horario activo y pasado el cooldown (SOUNDS_COOLDOWN_MINUTES, 45), elige un canal con al menos una persona (no cuenta el AFK) y un audio al azar. Se apaga conSOUNDS_ENABLED=false.
Cómo se cargan
/sonido-add(dev): permanente. mp3, ogg o wav, hasta 2 MB./canjear-sonido(rol puntos): temporal, pagado con puntos. Ver abajo.- Los audios viven en
SOUNDS_DIR, fuera de git. Dueño y vencimiento de los canjeados quedan enSOUNDS_DIR/_meta.json; un sonido sin entrada ahí es permanente.
Puntos
Los miembros con POINTS_ROLE_ID juntan puntos y los canjean. Sin ese rol configurado, el módulo no se carga.
Cómo se ganan
- Voz: 1 punto cada 5 minutos a cada miembro con el rol que esté en un canal de voz con al menos otro humano (no cuenta el canal AFK ni estar ensordecido). Tope: 60 por día.
- LoL: 5 por cada partida nueva que se guarda y 5 más si la ganaste. El dedup de la ingesta garantiza que cada partida se paga una sola vez.
- A mano: un dev puede sumar o restar con
/puntos-dar.
Canje: un sonido propio
/canjear-sonido <nombre> <audio> cuesta 100 puntos: el audio puede durar hasta 8 s, queda cargado 7 días y se borra solo al vencer. Máximo 1 activo por persona (lo podés borrar antes con /sonido-del). El bot mide la duración con ffprobe y recién cobra si el audio pasa el chequeo, y avisa en el canal que canjeaste. Todos los números se cambian por variables de entorno.
Deploy
Local
python run.py directo, o .\scripts\run_bot.ps1 [-Environment production], que abre consola visible y espeja todo a logs\<ambiente>\. No levantes dos instancias contra el mismo ambiente/server: te responderían los comandos dos veces.
Server Linux (systemd)
El repo trae deploy/bogabot.service. El setup es una vez: clonar, venv + pip install -r requirements.txt, instalar ffmpeg, copiar el .env.production por scp (con permisos 600), instalar el service y systemctl enable --now bogabot. El estado (puntos, key de Riot, reinicio del ranking troll) vive en data/, fuera de git.
sudo apt install ffmpeg
sudo cp deploy/bogabot.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now bogabot
sudo journalctl -u bogabot -f # logs en vivoPara actualizar: git pull + pip install si cambió requirements.txt + systemctl restart bogabot. Cambiar la key de Riot no requiere deploy: /riot-key desde Discord. El repo trae además un workflow de GitHub Actions que despliega cada push a main que pasa los tests, pensado para cuando haya VPS.
Estado y límites
- Alcance: beta con el grupo. Módulos de LoL (ranking y trolls), sonidos, puntos y ayuda. Sin funciones de IA todavía — están en el backlog como cog aparte.
- Storage: hoy es Discord (mensajes JSON en un canal privado + índice en memoria). Es O(n) mensajes; migrar a una DB real es una clase nueva en
storage/y una línea enbot.py. Puntos y sonidos canjeados van a archivos JSON endata/ysounds/. - Colas: el ranking diario y semanal cuenta solo Ranked (Solo/Duo y Flex); el recap “Trolls y Pros”, solo Flex. El detector de trolls y los puntos miran todas las colas.
- Región: decisión tomada para LAS (
la2/americas); configurable para otras. - Tests:
python -m pytest— scoring, dedup, mapper de match-v5 con timeline, reglas troll, config, ranking troll, ingesta y ruteo de avisos.
Bugs, ideas y pedidos → issues del repo.