Ir al contenido

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.

Solo dashboard
AutenticaciónRequiere sesión OAuth del panel (cookie HttpOnly). No uses la API Key de bot en el navegador 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).

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

POSThttps://ttv.losperris.dev/api/dashboard/overlay-link
ParámetroTipoRequeridoDescripción
toolStringtrends
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

GEThttps://ttv.losperris.dev/api/dashboard/overlay-state/trends

Lee 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"

  }

}
PUThttps://ttv.losperris.dev/api/dashboard/overlay-state/trends
ParámetroTipoRequeridoDescripción
stateObjectJSON 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"

  }

}
  1. En el panel, pulsa Overlay y copia la URL (incluye overlayToken de solo lectura).
  2. En OBS, añade una fuente Navegador (Browser Source).
  3. Pega la URL, usa 900 × 580 px (o el ancho de tu escena) y fondo transparente.
  4. Marca Actualizar navegador cuando la escena se active.
  5. En el panel, configura la duración (1–60 min, por defecto 5) y pulsa Play para iniciar el temporizador.
  • 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.

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. !hola cuenta como hola).
  • 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.).

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 }