CreaRack-SL

Digital Signage — Flujo SpinetiX

Conceptoactiveverificado 2026-04-21#signage#spinetix#deployment#svg

Digital Signage — Flujo SpinetiX

Qué es

Pipeline completo para publicar contenido multimedia en reproductores SpinetiX HMP (Hyper Media Player). Abarca desde composición de proyecto SVG dinámico hasta descarga autónoma por el dispositivo físico, sin requerir conexión permanente con el servidor.

Por qué existe

Los SpinetiX usan Scheduled Download: consultan periódicamente una URL HTTP para obtener índice WebDAV (spx-listing.xml) y descargan solo archivos cambiados. Esto exige endpoints públicos sin autenticación de sesión, identificados por token UUID (publish_token) por SignagePlayer. El módulo resuelve el contrato para que el reproductor opere autónomo incluso con NAT o cortafuegos.

Componentes

SpinetiXAdapter (signage/services/adapters/spinetix.py): adapter async con 2 protocolos:

  • JSON-RPC sobre HTTP POST en /rpc: getStatus, setPlaylist, setSchedule, getPlaybackLog, reboot. Payload {"jsonrpc": "2.0", "method": ..., "params": ..., "id": 1}, timeout 10s.
  • WebDAV PUT sobre /content/<filename>: sube archivos binarios via aiohttp con HTTP Basic, timeout 120s. push_content() acepta 200/201/204.
  • Screenshot GET /screenshot para proof-of-play visual.

Auth opcional: si credentials["username"] existe, aiohttp.BasicAuth.

SVG Composer (signage/services/svg_composer.py): genera SVG completo compatible SpinetiX desde items de playlist.

  • Namespace xmlns:spx="http://www.spinetix.com/namespace/1.0/spx" + spx:repeatCount para loop nativo HMP.
  • Cada slide → elemento SVG (<image>, <video>, <text>, <rect>, <iframe>) con animaciones de visibility/opacity como fracciones del tiempo total (keyTimes).
  • Transiciones: dissolve/fade (animate opacity), slide_left/right/up/down y zoom_in/out (animateTransform), none (visibility toggle).
  • Capas always_visible (overlays, tickers, logos) se renderizan sobre slides sin animación.
  • Vídeos: <video xlink:href="..." repeatCount="indefinite"/>, nunca sobreescribe duración con playback global.

Scheduled Download — endpoints públicos (signage/views_publish.py): bajo /signage/publish/<token>/ sin CSRF ni auth de sesión:

EndpointFunción
spx-listing.xml (o PROPFIND raíz)DAV:multistatus XML con project.svg, index.svg y media files, con size, content-type, ETag
project.svg / index.svgGenera SVG dinámico en tiempo real via compose_project_svg()
<filename>Sirve binario del MediaAsset via FileResponse

Cada request a spx_listing actualiza last_heartbeat y status="online" del player (proof-of-life pasivo). Si hay current_schedule, se evalúa con scheduling.engine.evaluate_schedule() para determinar playlist activa antes de componer SVG.

Despliegue activo (signage/services/deployment.py): execute_deployment(deployment_id) punto de entrada del task Huey. Modo push:

  1. Carga ContentDeployment, pone estado deploying.
  2. Resuelve IP del player desde device_profile o monitoring_target.
  3. Descifra credenciales sensibles (password, api_key, token) con CredentialManager.safe_decrypt.
  4. Instancia adapter correcto via registry.get_adapter(slug, ip, creds, config).
  5. Ejecuta en nuevo event loop: push_content() por cada archivo + set_playlist() + set_schedule() si aplica.
  6. Agrega resultados por player (ok/partial/error) y actualiza deployment_results.

Estado final: deployed, failed o partial.

Flujos

Scheduled Download (principal SpinetiX):

Operador → edita Playlist → asigna a SignagePlayer (current_playlist)
SpinetiX HMP → GET /signage/publish/<token>/spx-listing.xml (periódico)
  → _get_playlist_items() resuelve MediaAssets
  → compose_project_svg() genera project.svg dinámico
  → respuesta DAV:multistatus con ETags
HMP → compara ETags, descarga solo archivos nuevos
  → GET /signage/publish/<token>/project.svg
  → GET /signage/publish/<token>/<imagen_o_video>
HMP → reproduce nativamente (animaciones SVG + spx:repeatCount)
Cada fetch → actualiza last_heartbeat (proof-of-life)

Despliegue activo (push para otros adapters):

API POST /api/signage/deployments/ → Huey → execute_deployment(id)
  → _deploy_to_player() por cada player
      → adapter.push_content() via WebDAV
      → adapter.set_playlist() via JSON-RPC
      → adapter.set_schedule() via JSON-RPC
  → ContentDeployment.status = deployed|partial|failed

Proof-of-play:

  • Pasivo: cada fetch SpinetiX actualiza last_heartbeat y status.
  • Activo: SpinetiXAdapter.get_playback_logs(since=...) via JSON-RPC getPlaybackLog; take_screenshot() captura desde /screenshot.
  • entity--signage--model--signageplayer — contiene publish_token, current_playlist/schedule, last_heartbeat.
  • entity--signage--model--mediaasset — archivos referenciados.
  • entity--signage--model--playlist — lista ordenada con asset_id, duration_seconds, transition.

Véase también

  • [[entity—signage—model—signageplayer]]
  • [[entity—signage—model—mediaasset]]
  • [[entity—signage—model—playlist]]