Skip to content

Arquitectura técnica

Visión general

Stack técnico

ComponenteTecnologíaRol
Framework desktopTauri 2.x (Rust)Ventana nativa, IPC, empaquetado
InterfazVue.js 3 + Composition APIUI reactiva
Estado globalPiniaGestión de estado
Internacionalizaciónvue-i18nFR / EN / ES / JA
ComunicaciónWebSocket (tokio-tungstenite)Overlay OBS + Stream Deck
Tests unitariosVitestComposables, stores
Tests E2EPlaywrightFlujos completos

Los cuatro componentes

1. Aplicación principal (Tauri)

El corazón del sistema. El usuario gestiona su setlist, configura sus platos y controla la reproducción aquí. Cualquier cambio dispara un broadcast WebSocket a todos los clientes conectados.

Construida con Vue.js 3 en el lado UI y Rust en el backend. Tauri une ambos mediante comandos IPC tipados.

2. OBS Overlay

Un simple archivo HTML (obs-overlay/index.html) añadido como Fuente Navegador en OBS Studio. Se conecta al WebSocket de la app y actualiza la pantalla con cada mensaje PLAYING_UPDATE. No se requiere servidor externo — todo pasa por localhost.

3. Plugin Stream Deck

Un plugin JavaScript para Elgato Stream Deck. Cada botón representa un plato. Se conecta al mismo WebSocket y envía comandos de vuelta (TOGGLE_DECK, PLAY_TRACK, STOP_DECK). Los botones se actualizan dinámicamente (portada, título, estado playing/idle).

4. Widget npm dlp-player

Un paquete JavaScript independiente (publicación en npm pendiente). Lee un JSON de playlist exportado desde DLP y sincroniza la visualización de los temas con un reproductor multimedia (<video>, <audio>, iframe de YouTube o SoundCloud). Dos modos de visualización: list (tracklist junto al reproductor) y overlay (superpuesto en la parte inferior). Sin dependencia de la app de escritorio — funciona completamente del lado del cliente.

El servidor WebSocket

El backend Rust inicia un servidor WebSocket en localhost:9876 al lanzar la app. Gestiona:

  • Conexiones múltiples — OBS Overlay + Stream Deck pueden estar conectados simultáneamente
  • Broadcast — cuando cambia un tema, todos los clientes reciben PLAYING_UPDATE
  • Sincronización de config — el plugin Stream Deck envía GET_DECKS_CONFIG al inicio para obtener los platos configurados

Protocolo

Cualquier cliente WebSocket puede conectarse — sin autenticación, el servidor es solo local.

javascript
const ws = new WebSocket('ws://localhost:9876')

ws.onmessage = (event) => {
  const { type, payload } = JSON.parse(event.data)
  if (type === 'PLAYING_UPDATE') {
    // Actualizar la pantalla
  }
}

Mensajes salientes (App → Clientes)

PLAYING_UPDATE — Enviado cuando cambian los temas en reproducción.

json
{
  "type": "PLAYING_UPDATE",
  "payload": {
    "tracks": [
      {
        "id": "uuid",
        "title": "Título del tema",
        "artist": "Nombre del artista",
        "image": "data:image/jpeg;base64,... o URL",
        "deckName": "Vinyl 1",
        "qrCodeUrl": "https://..."
      }
    ]
  }
}

DECK_CANDIDATES — Respuesta a GET_DECK_CANDIDATES. Proporciona los temas disponibles para un plato dado.

json
{
  "type": "DECK_CANDIDATES",
  "payload": {
    "deckId": "deck-1",
    "currentlyPlaying": { "id": "...", "title": "...", "artist": "...", "image": "..." },
    "lastPlayed":       { "id": "...", "title": "...", "artist": "...", "image": "..." },
    "nextUnplayed":     { "id": "...", "title": "...", "artist": "...", "image": "..." }
  }
}

DECKS_CONFIG — Respuesta a GET_DECKS_CONFIG. Lista todos los platos configurados.

json
{
  "type": "DECKS_CONFIG",
  "payload": {
    "decks": [
      { "id": "deck-1", "name": "Vinyl 1", "deckType": "vinyl", "image": "data:image/png;base64,..." },
      { "id": "deck-2", "name": "CDJ 1",   "deckType": "cd",    "image": "data:image/png;base64,..." }
    ]
  }
}

CONFIG_UPDATE — Enviado cuando cambia la configuración visual del overlay (tema, opciones de visualización, animaciones).

Mensajes entrantes (Clientes → App)

MensajePayloadDescripción
GET_DECKS_CONFIG{}Solicitar la lista de platos configurados
TOGGLE_DECK{ "deck_id": "deck-1" }Activar/desactivar un plato
GET_DECK_CANDIDATES{ "deck_id": "deck-1" }Solicitar temas candidatos para un plato
PLAY_TRACK{ "track_id": "uuid" }Iniciar la reproducción de un tema
STOP_DECK{ "deck_id": "deck-1" }Detener un plato

Tipos de plato

ValorDescripción
vinylPlato de vinilo
cdReproductor CD / CDJ
controllerControlador DJ
softwareSoftware (Rekordbox, Serato, Traktor...)

Gestión de versiones

La versión se define una sola vez en package.json y se sincroniza automáticamente con tauri.conf.json y Cargo.toml mediante un script sync-version.js, llamado automáticamente antes de cada build y tauri mediante los hooks npm prebuild / pretauri.