Arquitectura técnica
Visión general
Stack técnico
| Componente | Tecnología | Rol |
|---|---|---|
| Framework desktop | Tauri 2.x (Rust) | Ventana nativa, IPC, empaquetado |
| Interfaz | Vue.js 3 + Composition API | UI reactiva |
| Estado global | Pinia | Gestión de estado |
| Internacionalización | vue-i18n | FR / EN / ES / JA |
| Comunicación | WebSocket (tokio-tungstenite) | Overlay OBS + Stream Deck |
| Tests unitarios | Vitest | Composables, stores |
| Tests E2E | Playwright | Flujos 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_CONFIGal inicio para obtener los platos configurados
Protocolo
Cualquier cliente WebSocket puede conectarse — sin autenticación, el servidor es solo local.
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.
{
"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.
{
"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.
{
"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)
| Mensaje | Payload | Descripció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
| Valor | Descripción |
|---|---|
vinyl | Plato de vinilo |
cd | Reproductor CD / CDJ |
controller | Controlador DJ |
software | Software (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.

