b877a32ad8
Two new additive widget kinds: Jellyfin 'now_playing': like the existing 'activity' widget but filters to only sessions with active playback (NowPlayingItem present + not paused). Shows who's actually watching right now. The 'activity' kind is unchanged (shows all sessions including idle). Grafana 'panel': embeds a single Grafana panel directly in the app via an iframe, using Grafana's /d-solo/ endpoint (renders one panel without dashboard chrome, kiosk=tv). Configurable dashboard_uid, panel_id, and time range (from/to, defaults now-1h/now). Includes a fallback 'Open in Grafana' link for when embedding is blocked by X-Frame-Options/CSP. The 'link' kind is unchanged (still builds a deep-link URL). Backend: new widget configs + definitions on jellyfin/grafana; source adapter logic (session filter for now_playing; d-solo embed URL for panel); 6 new tests. Frontend: JellyfinNowPlayingWidget + GrafanaPanelWidget components; registry bindings; 6 new tests. 278 backend tests pass (+6); 127 frontend tests pass (+6); lint/build green both sides.
72 lines
1.9 KiB
Python
72 lines
1.9 KiB
Python
"""Jellyfin service definition."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from media_library_viewer_api.integrations.base import (
|
|
SecretField,
|
|
ServiceBaseUrl,
|
|
ServiceConfigBase,
|
|
ServiceDefinition,
|
|
WidgetConfigBase,
|
|
widget_kind,
|
|
)
|
|
|
|
|
|
class JellyfinConfig(ServiceConfigBase):
|
|
"""Non-secret Jellyfin connection config.
|
|
|
|
The optional ``jellyseerr_url`` / ``jellyseerr_api_key`` fields carry the
|
|
paired Jellyseerr companion config, absorbed from the former standalone
|
|
``jellyseerr`` service type (see OpenSpec change ``services-as-hub-ia``).
|
|
When both are set, the Jellyfin service page renders a Requests tab backed
|
|
by Jellyseerr.
|
|
"""
|
|
|
|
base_url: ServiceBaseUrl
|
|
user_id: str = ""
|
|
timeout_seconds: int = 10
|
|
jellyseerr_url: str = ""
|
|
jellyseerr_api_key: str = ""
|
|
|
|
|
|
class JellyfinActivityWidgetConfig(WidgetConfigBase):
|
|
"""Live Jellyfin session activity."""
|
|
|
|
# No user-overridable fields; the service record carries user_id.
|
|
pass
|
|
|
|
|
|
class JellyfinNowPlayingWidgetConfig(WidgetConfigBase):
|
|
"""Only show sessions with active playback (not idle/paused)."""
|
|
|
|
pass
|
|
|
|
|
|
DEFINITION = ServiceDefinition(
|
|
service_type="jellyfin",
|
|
name="Jellyfin",
|
|
description="Media server with live session activity.",
|
|
config_model=JellyfinConfig,
|
|
secret_fields=[
|
|
SecretField(key="api_key", label="API key", required=True),
|
|
],
|
|
widget_kinds=[
|
|
widget_kind(
|
|
kind="activity",
|
|
name="Activity",
|
|
description="Live sessions and idle users.",
|
|
model_cls=JellyfinActivityWidgetConfig,
|
|
default_config={},
|
|
refresh_interval_ms=30_000,
|
|
),
|
|
widget_kind(
|
|
kind="now_playing",
|
|
name="Now Playing",
|
|
description="Only sessions actively playing media.",
|
|
model_cls=JellyfinNowPlayingWidgetConfig,
|
|
default_config={},
|
|
refresh_interval_ms=30_000,
|
|
),
|
|
],
|
|
)
|