Integración externa - Jellyfin / Emby

¡Hola a todos :waving_hand:

Como se anunció en el tema de las integraciones de Home Assistant a llevar, aquí tenéis Jellyfin & Emby: una sola integración para los dos servidores (Jellyfin es un fork de Emby, la API es común), que detecta automáticamente a qué servidor se está accediendo. @AlexTrovato, esto es tu solicitud de agosto :wink:

[captura del panel de control]

¿Qué hace?

Un dispositivo por reproductor (aplicación de TV, teléfono, navegador):

  • :play_button: reproducción, pausa, stop, anterior, siguiente, retroceso y avance rápido, volumen, silencio
  • :musical_note: el estado de reproducción, compatible con el widget Música del panel de control
  • :label: el título actual y el tiempo restante
  • :sparkles: « durante la intro » y « durante los créditos »: bajo Jellyfin 10.10+ con un plugin de segmentos (Chapter Segments Provider, Intro Skipper…), bajo Emby con su detección de intros

Un dispositivo servidor: reproducciones en curso, transcodificaciones, un resumen « quién está viendo qué » y un contador por biblioteca.

:bullseye: Escenas

Cuatro disparadores, Reproducción iniciada / en pausa / reanudada / detenida, filtrables por reproductor y por tipo de medio (película, episodio, música, TV en vivo…):

:clapper_board: Una película comienza en la TV del salón → luces atenuadas
:pause_button: Pausa → se encienden

Y dos acciones de escena:

  • :bell: Mostrar un mensaje en un reproductor: « Alguien está en la puerta » encima de la película
  • :popcorn: Reproducir un medio en un reproductor: busca un título en la biblioteca (película, serie, álbum, artista, lista de reproducción) y lo reproduce, al azar si es necesario

:framed_picture: Widgets

  • En reproducción: quién está viendo qué, dónde, con los pósters
  • Reproductor: la reproducción en curso en el control remoto (imagen de fondo, título, tiempo restante, botones). Configuración vacía = sigue lo que se está reproduciendo; o elija un reproductor específico
  • Últimos añadidos: los pósters de las últimas películas, series o álbumes, los nuevos episodios agrupados por serie

Instalación

:warning: Gladys 5.1 mínimo.

  1. Cree una clave de API para Gladys: en Jellyfin, Panel de control → Claves API; en Emby, Configuración → Avanzado → Claves API
  2. En Gladys: Integraciones → Multimedia → Jellyfin & Emby
  3. Ingrese la URL del servidor (http://ip-del-servidor:8096, o su dirección https) y la clave, luego Probar la conexión
  4. Pestaña Descubrimiento: agregue el servidor y sus reproductores

Un reproductor solo aparece cuando está conectado al servidor: abra la aplicación en la TV, luego haga clic en « Buscar reproductores ».

Lo que me gustaría que probarais :folded_hands:

Lo he probado en Jellyfin 10.11 y 12.1 y en Emby 4.10, con un reproductor simulado. Me faltan las condiciones reales:

  • sus aplicaciones de TV (Android TV, Fire TV, LG, Samsung…): los botones, el volumen, el mensaje en pantalla
  • Emby: todo, y en particular la intro y los créditos
  • un servidor detrás de un reverse proxy: si el WebSocket no pasa, la integración se basa en una consulta cada 15 s (avíseme si es así, los registros lo indican)

En caso de problemas, los registros de la integración, visibles en Gladys, me ayudan enormemente.

Es una 0.2.0: la 1.0 vendrá con sus comentarios. Código, documentación FR/EN y pruebas: GitHub - guim31/gladys-jellyfin · GitHub

Hola y gracias :television:

Probado con mi servidor Jellyfin detrás de un proxy (pero el websocket funciona) :white_check_mark:
Dispositivos descubiertos y añadidos con éxito.
Los widgets muestran correctamente los reproductores/reproducciones en curso y los últimos añadidos :star_struck:
Las acciones y desencadenantes funcionan excepto la de enviar un mensaje (probado con el cliente oficial de iPhone y Apple TV oficial).
Las funciones de Pausa/Reproducción y Stop funcionan bien en el widget (pero con algunos segundos de latencia en el retorno del estado). Sin embargo, nada con el botón siguiente.

Aquí están mis registros:

[2026-09-27T20:31:16.413Z] [INFO] Iniciando la integración de Jellyfin & Emby v0.2.0...
[2026-09-27T20:31:17.027Z] [INFO] [gladys-sdk] conectado a Gladys (http://172.30.0.1:80)
[2026-09-27T20:31:17.119Z] [INFO] Esperando la configuración (URL del servidor + clave API)
[2026-09-27T20:32:03.208Z] [INFO] onConfigUpdated -> nueva configuración recibida
[2026-09-27T20:32:03.401Z] [INFO] [media-monitor] Conectado al servidor Jellyfin "99b9829bee05" (v12.1.0)
[2026-09-27T20:32:03.478Z] [INFO] [media-monitor] Nuevo reproductor descubierto: Firefox (Jellyfin Web)
[2026-09-27T20:32:03.871Z] [INFO] [media-socket] Socket en tiempo real conectado
[2026-09-27T20:32:07.675Z] [INFO] [media-monitor] Conectado al servidor Jellyfin "99b9829bee05" (v12.1.0)
[2026-09-27T20:32:07.694Z] [INFO] [media-monitor] Nuevo reproductor descubierto: Firefox (Jellyfin Web)
[2026-09-27T20:32:39.225Z] [INFO] [media-monitor] Nuevo reproductor descubierto: iPhone de Cyril (Jellyfin iOS)
[2026-09-27T20:32:39.382Z] [INFO] [media-monitor] Evento de escena playback_started: Severance - S01E02 - Semi-bucle en iPhone de Cyril
[2026-09-27T20:32:50.765Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf
[2026-09-27T20:32:52.309Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:server:76b6e7325e104d378c17f1432a1a0dde
[2026-09-27T20:35:20.643Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:20.731Z] [INFO] [media-monitor] Comando de pausa enviado a iPhone de Cyril
[2026-09-27T20:35:29.191Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:29.243Z] [INFO] [media-monitor] Comando de pausa enviado a iPhone de Cyril
[2026-09-27T20:35:35.099Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:stop = 1
[2026-09-27T20:35:35.176Z] [INFO] [media-monitor] Comando de parada enviado a iPhone de Cyril
[2026-09-27T20:35:50.401Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:50.479Z] [INFO] [media-monitor] Comando de pausa enviado a iPhone de Cyril
[2026-09-27T20:37:57.838Z] [INFO] [media-monitor] Mensaje mostrado en iPhone de Cyril
[2026-09-27T20:38:27.762Z] [INFO] [media-monitor] Reproduciendo "Vaiana, la leyenda del fin del mundo (2016)" en iPhone de Cyril
[2026-09-27T20:38:31.917Z] [INFO] [media-monitor] Reproduciendo "Vaiana, la leyenda del fin del mundo (2016)" en iPhone de Cyril
[2026-09-27T20:39:26.866Z] [INFO] [media-monitor] Evento de escena playback_paused: Severance - S01E02 - Semi-bucle en iPhone de Cyril
[2026-09-27T20:39:30.246Z] [INFO] [media-monitor] Nuevo reproductor descubierto: AppleTV (Swiftfin tvOS)
[2026-09-27T20:39:40.014Z] [INFO] [media-monitor] Reproduciendo "Vaiana, la leyenda del fin del mundo (2016)" en iPhone de Cyril
[2026-09-27T20:40:11.116Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c
[2026-09-27T20:40:26.749Z] [INFO] [media-monitor] Reproduciendo "Severance" en AppleTV
[2026-09-27T20:40:32.684Z] [INFO] [media-monitor] Evento de escena playback_started: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:41:01.842Z] [INFO] [media-monitor] Evento de escena playback_paused: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:41:14.032Z] [INFO] [media-monitor] Evento de escena playback_resumed: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:41:29.032Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:41:29.120Z] [INFO] [media-monitor] Comando de pausa enviado a AppleTV
[2026-09-27T20:41:31.034Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:41:31.042Z] [INFO] [media-monitor] Comando de pausa enviado a AppleTV
[2026-09-27T20:41:34.246Z] [INFO] [media-monitor] Evento de escena playback_paused: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:41:35.699Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:play = 1
[2026-09-27T20:41:35.709Z] [INFO] [media-monitor] Comando de reproducción enviado a AppleTV
[2026-09-27T20:41:40.846Z] [INFO] [media-monitor] Evento de escena playback_resumed: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:41:48.766Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:next = 1
[2026-09-27T20:41:48.843Z] [INFO] [media-monitor] Comando siguiente enviado a AppleTV
[2026-09-27T20:41:58.735Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:stop = 1
[2026-09-27T20:41:58.793Z] [INFO] [media-monitor] Comando de parada enviado a AppleTV
[2026-09-27T20:41:58.923Z] [INFO] [media-monitor] Evento de escena playback_stopped: Severance - S01E01 - El lado bueno del infierno en AppleTV
[2026-09-27T20:42:11.278Z] [INFO] [media-monitor] Evento de escena playback_started: Severance - S01E02 - Semi-bucle en AppleTV
[2026-09-27T20:42:15.261Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:42:15.352Z] [INFO] [media-monitor] Comando de pausa enviado a AppleTV
[2026-09-27T20:42:20.614Z] [INFO] [media-monitor] Evento de escena playback_paused: Severance - S01E02 - Semi-bucle en AppleTV

¡Genial los comentarios, lo miro mañana!

La 0.2.1 está disponible, aquí está lo que tus comentarios han dado:

:next_track_button: El botón Siguiente: Swiftfin (como Jellyfin para Android TV) solo avanza si tiene una lista de reproducción, lo cual no es el caso de un episodio lanzado solo. Ahora, en un episodio, Siguiente y Anterior solicitan al servidor el episodio vecino y lo lanzan directamente. Funciona en todas partes donde la acción « Reproducir un medio » funciona, y funcionaba en tu caso :wink:

:stopwatch: La latencia en el estado: en tus registros, la aplicación señala su pausa aproximadamente 5 segundos después del comando, y Gladys limita la actualización de un widget a una vez cada 10 segundos. Dos cambios: los botones del widget Reproductor ahora usan « acciones de widget », que Gladys recarga tan pronto como se presiona, y el estado esperado se muestra de inmediato antes de ser confirmado por la aplicación. ¡Fin del doble clic :grinning_face_with_smiling_eyes:

:bell: El mensaje: aquí, no es la integración, el servidor recibe bien el comando (« Mensaje mostrado » en tus registros). Es la aplicación la que elige mostrarlo:

  • Swiftfin aún no maneja los mensajes (es literalmente un TODO en su código :sweat_smile:)
  • la aplicación oficial de iOS no lo muestra durante un video
  • el cliente web y Jellyfin para Android TV lo muestran bien

Ahora está especificado en la documentación y en la descripción de la acción.

¡Dime si es mejor en tu caso!

Botón Siguiente :white_check_mark:
Latencia :white_check_mark: es hiper reactivo
Mensaje :white_check_mark: en un cliente Web

Gracias :handshake:

¡Vaya, eso es genial! :+1: