Files
manage/backend/src/media_library_viewer_api/integrations/jellyfin.py
T
Developer b3b167c075 Backend: add backups + authentik service types, absorb jellyseerr (Slice 1)
New service types:
- backups: BackupsConfig(ingestion_label), no secrets, summary widget kind.
  Modeled as a service so it can be named/multi-instanced like others.
- authentik: AuthentikConfig(base_url, timeout_seconds), api_token secret
  (required). Directory source for the upcoming Users tab.

Jellyseerr absorption:
- JellyfinConfig gains optional jellyseerr_url + jellyseerr_api_key fields.
- integrations/jellyseerr.py deleted; registry entry removed.
- clients/jellyseerr.py stays (JellyseerrClient still used by enrichment).
- One-time idempotent migration in settings_store.ensure_defaults():
  jellyseerr service rows merge into a paired Jellyfin (exactly-one merges;
  multiple picks first unpaired; none/all-paired drops with a logged
  warning). The api_key is decrypted from secrets before moving to config.

Registry is now 8 types: alertmanager, authentik, backups, grafana,
jellyfin, nextcloud, prometheus, ssh_tasks.

Tests: registry count updated to 8, jellyseerr-absent assertion, new-type
definition assertions, and migration tests (single-jellyfin merge, no-
jellyfin drop, idempotency). 256 backend tests pass; ruff clean.

Refs openspec/changes/services-as-hub-ia/ (spec R6, tasks slice 1).
2026-06-26 18:02:59 +00:00

58 lines
1.5 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
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,
),
],
)