soulsync/core/media_server/__init__.py
Broque Thomas f702196dca Phase 0: Add MediaServerClient contract + registry
`core/media_server/` package with the Protocol contract that
every media server client (Plex, Jellyfin, Navidrome, SoulSync
standalone) satisfies, plus the registry that holds them.

Required methods conservatively limited to the four every server
truly implements today: is_connected, ensure_connection,
get_all_artists, get_all_album_ids. Other generic methods
(search_tracks, trigger_library_scan, get_recently_added_albums,
etc.) are listed as OPTIONAL — present on most servers but not
all (SoulSync has no library-scan API since it walks the filesystem
directly; Jellyfin uses a different search shape). Phase B's
engine adapters route around the gaps with per-server fallback
instead of forcing every client to declare a no-op stub.

Same registry shape as the download plugin registry — single
source of truth for which servers exist + name resolution. Adding
a 5th server (Subsonic, Emby, etc.) becomes one register call
plus the new client class.

5 conformance tests pin every server class implements every
required method. Plan doc at docs/media-server-engine-refactor-plan.md.

Pure additive — no consumer routes through the contract or
registry yet. Suite still green (1921 passed).
2026-05-04 20:49:25 -07:00

23 lines
1 KiB
Python

"""Media server engine — central dispatch for the per-server clients
(Plex, Jellyfin, Navidrome, SoulSync standalone).
Companion to the download engine refactor — same architectural
shape applied to the read-side of the library. The orchestrator
historically had 33+ ``if active_server == 'plex' / 'jellyfin' /
...`` dispatch sites in web_server.py. This package replaces those
with a single ``MediaServerEngine.method()`` call per operation.
Per-server clients keep their protocol-specific work (Plex's
PlexAPI SDK, Jellyfin's REST endpoints, Navidrome's OpenSubsonic
API, SoulSync's filesystem walk). The engine just routes by
``active_server`` config + provides a uniform shape for the calls
``web_server.py`` makes generically.
See ``docs/media-server-engine-refactor-plan.md`` for the full
phased plan.
"""
from core.media_server.contract import MediaServerClient
from core.media_server.registry import MediaServerRegistry, build_default_registry
__all__ = ["MediaServerClient", "MediaServerRegistry", "build_default_registry"]