C1: Migrate status-check dispatch sites to engine

Two sites in web_server.py replaced:
- /status route's media-server connectivity check (4-way if/elif
  for plex/jellyfin/navidrome/soulsync) → engine.is_connected()
- /api/playlists endpoint's server_connected check (3-way if/elif)
  → engine.is_connected()

Engine reads active_server config + dispatches to the right client
with internal connection caching preserved (the underlying clients
all cache is_connected() calls).

Engine constructor now accepts a pre-built clients={...} dict so
web_server.py wires the same instances as its existing per-client
globals — no double-init.

Suite still green. Per-server clients still accessible via
engine.client(name) for source-specific reaches.
This commit is contained in:
Broque Thomas 2026-05-04 21:25:20 -07:00
parent 6b54ca6598
commit 971d683ebd
2 changed files with 47 additions and 24 deletions

View file

@ -45,6 +45,7 @@ class MediaServerEngine:
self,
registry: Optional[MediaServerRegistry] = None,
active_server_resolver=None,
clients: Optional[Dict[str, Any]] = None,
) -> None:
"""Initialize the engine.
@ -56,9 +57,29 @@ class MediaServerEngine:
``config_manager.get_active_media_server``. Tests
inject a custom resolver to switch active server
without touching real config.
clients: Pre-built {name: client_instance} dict. When
provided, the engine wraps these instances directly
instead of asking the registry to construct fresh
ones. web_server.py uses this so the engine
shares the same client objects as the
pre-existing global variables (no double-init).
"""
self.registry = registry if registry is not None else build_default_registry()
self.registry.initialize()
if clients is not None:
# Wrap pre-built instances (production case from web_server.py
# init). Skip registry.initialize() — we already have the
# instances, just stash them in the registry's slots so
# registry.get(name) works.
for name, client in clients.items():
self.registry._instances[name] = client
# Mark any registered-but-not-supplied as failed init so
# active_client() returns None for them.
for name in self.registry._specs:
if name not in self.registry._instances:
self.registry._instances[name] = None
else:
self.registry.initialize()
if active_server_resolver is None:
from config.settings import config_manager

View file

@ -603,6 +603,23 @@ try:
except Exception as e:
logger.error(f" SoulSync library client failed to initialize: {e}")
# Build the MediaServerEngine on top of the per-client globals above.
# Engine wraps the same instances — no double-init. Provides
# ``engine.method()`` dispatch in place of the historic
# ``if active_server == 'plex' / 'jellyfin' / ...`` chains.
try:
from core.media_server import MediaServerEngine
media_server_engine = MediaServerEngine(clients={
'plex': plex_client,
'jellyfin': jellyfin_client,
'navidrome': navidrome_client,
'soulsync': soulsync_library_client,
})
logger.info(" Media server engine initialized")
except Exception as e:
logger.error(f" Media server engine failed to initialize: {e}")
media_server_engine = None
try:
soulseek_client = DownloadOrchestrator()
logger.info(" Download orchestrator initialized")
@ -3460,23 +3477,14 @@ def get_status():
metadata_status = get_metadata_status_snapshot(spotify_client=spotify_client)
# Test media server - use EXISTING instances (they have internal caching)
# Media server clients already cache connection checks internally
# Test media server — engine reads active_server config + dispatches
# to the right client (with internal connection caching). Engine
# returns False safely if the active client is None / not registered.
if current_time - _status_cache_timestamps['media_server'] > STATUS_CACHE_TTL:
media_server_start = time.time()
media_server_status = False
if active_server == "plex" and plex_client:
# Use existing instance - has 30s internal connection cache
media_server_status = plex_client.is_connected()
elif active_server == "jellyfin" and jellyfin_client:
# Use existing instance - has internal connection caching
media_server_status = jellyfin_client.is_connected()
elif active_server == "navidrome" and navidrome_client:
# Use existing instance
media_server_status = navidrome_client.is_connected()
elif active_server == "soulsync":
# Standalone mode — always connected if Transfer folder exists
media_server_status = soulsync_library_client.is_connected() if soulsync_library_client else False
media_server_status = (
media_server_engine.is_connected() if media_server_engine else False
)
media_server_response_time = (time.time() - media_server_start) * 1000
_status_cache['media_server'] = {
'connected': media_server_status,
@ -9293,15 +9301,9 @@ def get_artist_enhanced_detail(artist_id):
if album.get('thumb_url'):
album['thumb_url'] = fix_artist_image_url(album['thumb_url'])
# Include server type for sync option
# Include server type for sync option — engine routes to active client.
active_server = config_manager.get_active_media_server()
server_connected = False
if active_server == 'plex':
server_connected = plex_client.is_connected()
elif active_server == 'jellyfin':
server_connected = jellyfin_client.is_connected()
elif active_server == 'navidrome':
server_connected = navidrome_client.is_connected()
server_connected = media_server_engine.is_connected() if media_server_engine else False
result['server_type'] = active_server if server_connected else None
return jsonify(result)