Tendencias
Herramienta del panel que cuenta la primera palabra de cada mensaje del chat durante un temporizador. Muestra un ranking top 10 en tabla (posiciones, repeticiones y barras de progreso) en el dashboard y en OBS, sincronizados por la API del overlay.
Abre Tendencias en el panel. Usa el botón Overlay para copiar la URL firmada y controla la sesión desde el panel (OBS solo muestra el resultado).
Límites
Sección titulada «Límites»API del overlay
El panel genera un enlace firmado (overlayToken, scope overlay:read, válido 30 días) y sincroniza el estado entre el dashboard y OBS.
Generar enlace
https://ttv.losperris.dev/api/dashboard/overlay-link| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
tool | String | Sí | trends |
curl --request POST \
--url 'https://ttv.losperris.dev/api/dashboard/overlay-link' \
--header 'Content-Type: application/json' \
--cookie 'tu_sesion_dashboard' \
--data '{"tool":"trends"}'
{"url": "https://ttv.losperris.dev/overlay/trends?overlayToken=eyJ..."}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"url": "https://ttv.losperris.dev/overlay/trends?overlayToken=eyJ..."
}
{"success": false,"error": {"message": "Usuario no encontrado","code": "UNAUTHORIZED"}}
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"success": false,
"error": {
"message": "Usuario no encontrado",
"code": "UNAUTHORIZED"
}
}Estado compartido
https://ttv.losperris.dev/api/dashboard/overlay-state/trendsLee el estado publicado por el panel. El overlay en OBS usa el token de la URL; el panel usa la sesión del dashboard.
{"state": {"tracking": true,"remaining": 142,"timerEnded": false,"wordCounts": { "hola": 24, "gg": 18 },"minutes": 5,"displayName": "TuCanal","sessionActive": true,"timerEndsAt": 1752012234567,"updatedAt": 1752012234567}}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"state": {
"tracking": true,
"remaining": 142,
"timerEnded": false,
"wordCounts": { "hola": 24, "gg": 18 },
"minutes": 5,
"displayName": "TuCanal",
"sessionActive": true,
"timerEndsAt": 1752012234567,
"updatedAt": 1752012234567
}
}
{ "state": null }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{ "state": null }
{"success": false,"error": {"message": "Usuario no encontrado","code": "UNAUTHORIZED"}}
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"success": false,
"error": {
"message": "Usuario no encontrado",
"code": "UNAUTHORIZED"
}
}https://ttv.losperris.dev/api/dashboard/overlay-state/trends| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
state | Object | Sí | JSON con el estado de la herramienta (máx. 64 KB, máx. 200 claves). |
{ "success": true }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{ "success": true }
{"success": false,"error": {"message": "Solo el panel puede publicar el estado del overlay.","code": "FORBIDDEN"}}
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"success": false,
"error": {
"message": "Solo el panel puede publicar el estado del overlay.",
"code": "FORBIDDEN"
}
}Configuración en OBS
Sección titulada «Configuración en OBS»- En el panel, pulsa Overlay y copia la URL (incluye
overlayTokende solo lectura). - En OBS, añade una fuente Navegador (Browser Source).
- Pega la URL, usa 900 × 580 px (o el ancho de tu escena) y fondo transparente.
- Marca Actualizar navegador cuando la escena se active.
- En el panel, configura la duración (1–60 min, por defecto 5) y pulsa Play para iniciar el temporizador.
Cómo funciona
Sección titulada «Cómo funciona»- Temporizador: entre 1 y 60 minutos (valor por defecto: 5). Al pulsar Play empieza la cuenta atrás y se conecta al chat de tu canal.
- Ranking: tabla con las 10 palabras más repetidas, ordenadas por frecuencia. Las filas adoptan un diseño oscuro minimalista donde la barra de progreso utiliza el color morado de la marca (
primary). - Sincronización: si tienes varias pestañas del panel abiertas, solo la pestaña líder escucha el chat; el resto se sincroniza. El overlay en OBS lee el estado publicado por el panel.
- Fin de sesión: al terminar el temporizador, el panel muestra un toast con la palabra ganadora. El overlay sigue visible 30 segundos con el ranking final y luego se oculta (fondo transparente).
- Visibilidad en OBS: el overlay está oculto en reposo; aparece mientras el temporizador corre o justo después de terminar.
Conteo de palabras
Sección titulada «Conteo de palabras»Solo se analiza la primera palabra de cada mensaje (no todas las palabras ni emotes como entidades separadas):
- Se normaliza a minúsculas y se eliminan signos de puntuación al inicio (p. ej.
!holacuenta comohola). - Mínimo 3 caracteres tras la normalización.
- Se descartan stopwords en español (
el,la,que,como,http, etc.). - Se ignoran mensajes de bots conocidos (
nightbot,streamelements,fossabot,moobot,streamlabs, etc.).
Formato del estado (TrendsOverlayState)
Sección titulada «Formato del estado (TrendsOverlayState)»El panel publica este objeto en PUT /dashboard/overlay-state/trends y el overlay lo lee con GET:
{"state": {"tracking": true,"remaining": 142,"timerEnded": false,"wordCounts": {"hola": 24,"gg": 18},"minutes": 5,"displayName": "TuCanal","sessionActive": true,"timerEndsAt": 1752012345678,"updatedAt": 1752012234567}}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{
"state": {
"tracking": true,
"remaining": 142,
"timerEnded": false,
"wordCounts": {
"hola": 24,
"gg": 18
},
"minutes": 5,
"displayName": "TuCanal",
"sessionActive": true,
"timerEndsAt": 1752012345678,
"updatedAt": 1752012234567
}
}
{ "state": null }
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: public, s-maxage=10, stale-while-revalidate
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 29
X-RateLimit-Reset: 1710000060
{ "state": null }