MS Cin-3 + Cin-4: Route web_server through engine instead of per-client globals

Pre-change web_server.py had ~70 direct attribute reaches against the
per-server globals (plex_client.X, jellyfin_client.X, navidrome_client.X,
soulsync_library_client.X) plus ~60 standalone refs (truthy checks,
media_client assignments, source-name tuples). The engine was wired
but only used in 4 places, so most of the codebase still hand-dispatched
— the exact "partially defeats the purpose of this refactor" critique
Cin landed on the download PR initially.

- All ~70 client.attribute reaches migrated to
  media_server_engine.client('<name>').attribute. The chains in
  web_server.py do server-specific work (Plex raw API, Jellyfin /
  Navidrome client methods, all returning different shapes), so the
  if/elif structure stays — but the per-server CLIENT REACH now goes
  through the engine like Cin's POC pattern intended.
- All ~60 standalone refs migrated:
  - if plex_client → if media_server_engine.client('plex')
  - media_client = plex_client → media_client = media_server_engine.client('plex')
  - ('plex', plex_client) tuples → ('plex', media_server_engine.client('plex'))
- Per-server globals (plex_client / jellyfin_client / navidrome_client /
  soulsync_library_client) kept for now — external modules
  (PlaylistSyncService, WebScanManager, ListeningStatsWorker, search
  library check, discovery sync deps) still take them as kwargs.
  Dropping them entirely needs a follow-up sweep across those modules.

Suite green (1961 pass).
pull/497/head
Broque Thomas 3 weeks ago
parent 49f7679eef
commit 1bc5017592

@ -644,7 +644,7 @@ except Exception as e:
logger.error(f" Matching engine failed to initialize: {e}")
try:
sync_service = PlaylistSyncService(spotify_client, plex_client, soulseek_client, jellyfin_client, navidrome_client)
sync_service = PlaylistSyncService(spotify_client, plex_client, soulseek_client, jellyfin_client, media_server_engine.client('navidrome'))
logger.info(" Playlist sync service initialized")
except Exception as e:
logger.error(f" Playlist sync service failed to initialize: {e}")
@ -4154,12 +4154,12 @@ def handle_settings():
# Reload service clients with new settings (guard against None from partial init)
if spotify_client:
spotify_client.reload_config()
if plex_client:
plex_client.server = None
if jellyfin_client:
jellyfin_client.reload_config()
if navidrome_client:
navidrome_client.reload_config()
if media_server_engine.client('plex'):
media_server_engine.client('plex').server = None
if media_server_engine.client('jellyfin'):
media_server_engine.client('jellyfin').reload_config()
if media_server_engine.client('navidrome'):
media_server_engine.client('navidrome').reload_config()
# Reload orchestrator settings (download source mode, hybrid_primary, etc.)
if soulseek_client:
soulseek_client.reload_settings()
@ -5122,8 +5122,8 @@ def clear_plex_library_preference():
from database.music_database import MusicDatabase
db = MusicDatabase()
db.set_preference('plex_music_library', '')
if plex_client:
plex_client.music_library = None
if media_server_engine.client('plex'):
media_server_engine.client('plex').music_library = None
return jsonify({"success": True, "message": "Plex library preference cleared."})
except Exception as e:
logger.error(f"Error clearing Plex library preference: {e}")
@ -5134,7 +5134,7 @@ def clear_plex_library_preference():
def get_plex_music_libraries():
"""Get list of all available music libraries from Plex"""
try:
libraries = plex_client.get_available_music_libraries()
libraries = media_server_engine.client('plex').get_available_music_libraries()
# Get currently selected library
from database.music_database import MusicDatabase
@ -5143,8 +5143,8 @@ def get_plex_music_libraries():
# Get the currently active library name
current_library = None
if plex_client.music_library:
current_library = plex_client.music_library.title
if media_server_engine.client('plex').music_library:
current_library = media_server_engine.client('plex').music_library.title
return jsonify({
"success": True,
@ -5166,7 +5166,7 @@ def select_plex_music_library():
if not library_name:
return jsonify({"success": False, "error": "No library name provided"}), 400
success = plex_client.set_music_library_by_name(library_name)
success = media_server_engine.client('plex').set_music_library_by_name(library_name)
if success:
add_activity_item("", "Library Selected", f"Plex music library set to: {library_name}", "Now")
@ -5182,7 +5182,7 @@ def select_plex_music_library():
def get_jellyfin_users():
"""Get list of Jellyfin users that have music libraries"""
try:
users = jellyfin_client.get_available_users()
users = media_server_engine.client('jellyfin').get_available_users()
# Get currently selected user
from database.music_database import MusicDatabase
@ -5191,9 +5191,9 @@ def get_jellyfin_users():
# Determine the current user name from user_id
current_user = None
if jellyfin_client.user_id:
if media_server_engine.client('jellyfin').user_id:
for u in users:
if u['id'] == jellyfin_client.user_id:
if u['id'] == media_server_engine.client('jellyfin').user_id:
current_user = u['name']
break
@ -5217,7 +5217,7 @@ def select_jellyfin_user():
if not username:
return jsonify({"success": False, "error": "No username provided"}), 400
success = jellyfin_client.set_user_by_name(username)
success = media_server_engine.client('jellyfin').set_user_by_name(username)
if success:
add_activity_item("", "User Selected", f"Jellyfin user set to: {username}", "Now")
@ -5233,7 +5233,7 @@ def select_jellyfin_user():
def get_jellyfin_music_libraries():
"""Get list of all available music libraries from Jellyfin"""
try:
libraries = jellyfin_client.get_available_music_libraries()
libraries = media_server_engine.client('jellyfin').get_available_music_libraries()
# Get currently selected library
from database.music_database import MusicDatabase
@ -5242,10 +5242,10 @@ def get_jellyfin_music_libraries():
# Get the currently active library name (match Plex behavior)
current_library = None
if jellyfin_client.music_library_id:
if media_server_engine.client('jellyfin').music_library_id:
# Look up library name from ID
for lib in libraries:
if lib['key'] == jellyfin_client.music_library_id:
if lib['key'] == media_server_engine.client('jellyfin').music_library_id:
current_library = lib['title']
break
@ -5269,7 +5269,7 @@ def select_jellyfin_music_library():
if not library_name:
return jsonify({"success": False, "error": "No library name provided"}), 400
success = jellyfin_client.set_music_library_by_name(library_name)
success = media_server_engine.client('jellyfin').set_music_library_by_name(library_name)
if success:
add_activity_item("", "Library Selected", f"Jellyfin music library set to: {library_name}", "Now")
@ -5285,19 +5285,19 @@ def select_jellyfin_music_library():
def get_navidrome_music_folders():
"""Get list of available music folders from Navidrome"""
try:
if not navidrome_client:
if not media_server_engine.client('navidrome'):
return jsonify({"success": False, "error": "Navidrome client not configured"}), 400
folders = navidrome_client.get_music_folders()
folders = media_server_engine.client('navidrome').get_music_folders()
from database.music_database import MusicDatabase
db = MusicDatabase()
selected_folder = db.get_preference('navidrome_music_folder')
current_folder = None
if navidrome_client.music_folder_id:
if media_server_engine.client('navidrome').music_folder_id:
for f in folders:
if f['key'] == navidrome_client.music_folder_id:
if f['key'] == media_server_engine.client('navidrome').music_folder_id:
current_folder = f['title']
break
@ -5318,7 +5318,7 @@ def select_navidrome_music_folder():
data = request.get_json()
folder_name = data.get('folder_name', '')
success = navidrome_client.set_music_folder_by_name(folder_name)
success = media_server_engine.client('navidrome').set_music_folder_by_name(folder_name)
if success:
if folder_name:
@ -8046,9 +8046,9 @@ def test_automation_workflow():
results['media_clients'] = {'active_server': active_server}
for client_name, client in [
('plex', plex_client),
('jellyfin', jellyfin_client),
('navidrome', navidrome_client)
('plex', media_server_engine.client('plex')),
('jellyfin', media_server_engine.client('jellyfin')),
('navidrome', media_server_engine.client('navidrome'))
]:
try:
is_connected = client.is_connected() if client else False
@ -10810,7 +10810,7 @@ def _sync_tracks_to_server(track_rows, server_type):
if track_data.get('year'):
metadata['year'] = track_data['year']
if metadata:
success = plex_client.update_track_metadata(str(track_data['id']), metadata)
success = media_server_engine.client('plex').update_track_metadata(str(track_data['id']), metadata)
if success:
result['synced'] += 1
else:
@ -10825,7 +10825,7 @@ def _sync_tracks_to_server(track_rows, server_type):
elif server_type == 'jellyfin':
# Jellyfin: just trigger a library scan once after all file writes
try:
success = jellyfin_client.trigger_library_scan()
success = media_server_engine.client('jellyfin').trigger_library_scan()
if success:
result['synced'] = len(track_rows)
else:
@ -10853,8 +10853,8 @@ def _resolve_library_file_path(file_path):
# Also check the media server's music library path (handles Docker↔host path mismatch)
library_dirs = set()
try:
if plex_client and plex_client.server and plex_client.music_library:
for loc in plex_client.music_library.locations:
if media_server_engine.client('plex') and media_server_engine.client('plex').server and media_server_engine.client('plex').music_library:
for loc in media_server_engine.client('plex').music_library.locations:
library_dirs.add(loc)
except Exception:
pass
@ -11526,9 +11526,9 @@ def redownload_search_metadata(track_id):
if thumb_url and not thumb_url.startswith('http'):
_ab = ''
_at = ''
if plex_client and plex_client.server:
_ab = getattr(plex_client.server, '_baseurl', '') or ''
_at = getattr(plex_client.server, '_token', '') or ''
if media_server_engine.client('plex') and media_server_engine.client('plex').server:
_ab = getattr(media_server_engine.client('plex').server, '_baseurl', '') or ''
_at = getattr(media_server_engine.client('plex').server, '_token', '') or ''
if not _ab:
_pc = config_manager.get_plex_config()
_ab = (_pc.get('base_url', '') or '').rstrip('/')
@ -11834,12 +11834,12 @@ def sync_artist_library(artist_id):
if server_source:
media_client = None
if server_source == 'plex' and plex_client and plex_client.server:
media_client = plex_client
elif server_source == 'jellyfin' and jellyfin_client:
media_client = jellyfin_client
elif server_source == 'navidrome' and navidrome_client:
media_client = navidrome_client
if server_source == 'plex' and media_server_engine.client('plex') and media_server_engine.client('plex').server:
media_client = media_server_engine.client('plex')
elif server_source == 'jellyfin' and media_server_engine.client('jellyfin'):
media_client = media_server_engine.client('jellyfin')
elif server_source == 'navidrome' and media_server_engine.client('navidrome'):
media_client = media_server_engine.client('navidrome')
if media_client:
try:
@ -15122,11 +15122,11 @@ def _run_db_update_task(full_refresh, server_type):
media_client = None
if server_type == "plex":
media_client = plex_client
media_client = media_server_engine.client('plex')
elif server_type == "jellyfin":
media_client = jellyfin_client
media_client = media_server_engine.client('jellyfin')
elif server_type == "navidrome":
media_client = navidrome_client
media_client = media_server_engine.client('navidrome')
if not media_client:
_db_update_error_callback(f"Media client for '{server_type}' not available.")
@ -15168,11 +15168,11 @@ def _run_deep_scan_task(server_type):
media_client = None
if server_type == "plex":
media_client = plex_client
media_client = media_server_engine.client('plex')
elif server_type == "jellyfin":
media_client = jellyfin_client
media_client = media_server_engine.client('jellyfin')
elif server_type == "navidrome":
media_client = navidrome_client
media_client = media_server_engine.client('navidrome')
elif server_type == "soulsync":
# SoulSync standalone deep scan: find untracked files → move to Staging,
# remove stale DB records where files no longer exist on disk
@ -18045,10 +18045,10 @@ def get_server_playlists():
return jsonify({"success": False, "error": "No media server configured"}), 400
playlists_data = []
if active_server == 'plex' and plex_client and plex_client.is_connected():
if active_server == 'plex' and media_server_engine.client('plex') and media_server_engine.client('plex').is_connected():
# Use raw Plex API to get playlist metadata without fetching all tracks
try:
raw_playlists = plex_client.server.playlists()
raw_playlists = media_server_engine.client('plex').server.playlists()
logger.info(f"[ServerPlaylists] Plex returned {len(raw_playlists)} total playlists")
for playlist in raw_playlists:
if getattr(playlist, 'playlistType', None) == 'audio':
@ -18061,22 +18061,22 @@ def get_server_playlists():
except Exception as e:
logger.error(f"[ServerPlaylists] Error fetching Plex playlists: {e}", exc_info=True)
return jsonify({"success": False, "error": f"Plex error: {str(e)}"}), 500
elif active_server == 'jellyfin' and jellyfin_client and jellyfin_client.is_connected():
for pl in jellyfin_client.get_all_playlists():
elif active_server == 'jellyfin' and media_server_engine.client('jellyfin') and media_server_engine.client('jellyfin').is_connected():
for pl in media_server_engine.client('jellyfin').get_all_playlists():
playlists_data.append({
'id': pl.id,
'name': pl.title,
'track_count': pl.leaf_count,
})
elif active_server == 'navidrome' and navidrome_client and navidrome_client.is_connected():
for pl in navidrome_client.get_all_playlists():
elif active_server == 'navidrome' and media_server_engine.client('navidrome') and media_server_engine.client('navidrome').is_connected():
for pl in media_server_engine.client('navidrome').get_all_playlists():
playlists_data.append({
'id': pl.id,
'name': pl.title,
'track_count': pl.leaf_count,
})
else:
logger.warning(f"[ServerPlaylists] Server '{active_server}' not connected. plex_client={plex_client is not None}, jellyfin_client={jellyfin_client is not None}, navidrome_client={navidrome_client is not None}")
logger.warning(f"[ServerPlaylists] Server '{active_server}' not connected. plex_client={media_server_engine.client('plex') is not None}, jellyfin_client={media_server_engine.client('jellyfin') is not None}, navidrome_client={media_server_engine.client('navidrome') is not None}")
return jsonify({"success": False, "error": f"{active_server} not connected"}), 400
return jsonify({"success": True, "server_type": active_server, "playlists": playlists_data})
@ -18094,24 +18094,24 @@ def get_server_playlist_tracks(playlist_id):
# Get tracks from server
server_tracks = []
if active_server == 'plex' and plex_client:
if active_server == 'plex' and media_server_engine.client('plex'):
try:
# Try by ID first, fall back to name lookup (ID changes when playlist is recreated)
raw_playlist = None
try:
raw_playlist = plex_client.server.fetchItem(int(playlist_id))
raw_playlist = media_server_engine.client('plex').server.fetchItem(int(playlist_id))
except Exception:
pass
if not raw_playlist and playlist_name:
try:
raw_playlist = plex_client.server.playlist(playlist_name)
raw_playlist = media_server_engine.client('plex').server.playlist(playlist_name)
except Exception:
pass
if raw_playlist:
if not playlist_name:
playlist_name = raw_playlist.title
plex_base = getattr(plex_client.server, '_baseurl', '') or ''
plex_token = getattr(plex_client.server, '_token', '') or ''
plex_base = getattr(media_server_engine.client('plex').server, '_baseurl', '') or ''
plex_token = getattr(media_server_engine.client('plex').server, '_token', '') or ''
if not plex_base:
# Fallback: get from config
_pc = config_manager.get_plex_config()
@ -18136,9 +18136,9 @@ def get_server_playlist_tracks(playlist_id):
})
except Exception as e:
logger.error(f"[ServerPlaylistTracks] Plex error: {e}", exc_info=True)
elif active_server == 'jellyfin' and jellyfin_client:
tracks = jellyfin_client.get_playlist_tracks(playlist_id)
jf_base = jellyfin_client.base_url or ''
elif active_server == 'jellyfin' and media_server_engine.client('jellyfin'):
tracks = media_server_engine.client('jellyfin').get_playlist_tracks(playlist_id)
jf_base = media_server_engine.client('jellyfin').base_url or ''
for t in (tracks or []):
raw = t._data if hasattr(t, '_data') else {}
artists = raw.get('Artists', [])
@ -18153,8 +18153,8 @@ def get_server_playlist_tracks(playlist_id):
'duration': t.duration,
'thumb': thumb,
})
elif active_server == 'navidrome' and navidrome_client:
tracks = navidrome_client.get_playlist_tracks(playlist_id)
elif active_server == 'navidrome' and media_server_engine.client('navidrome'):
tracks = media_server_engine.client('navidrome').get_playlist_tracks(playlist_id)
for t in (tracks or []):
raw = t._data if hasattr(t, '_data') else {}
# Navidrome cover art via Subsonic API
@ -18179,9 +18179,9 @@ def get_server_playlist_tracks(playlist_id):
# Build server art URL prefix for resolving relative thumb paths
_art_prefix = ''
_art_suffix = ''
if active_server == 'plex' and plex_client and plex_client.server:
_ab = getattr(plex_client.server, '_baseurl', '') or ''
_at = getattr(plex_client.server, '_token', '') or ''
if active_server == 'plex' and media_server_engine.client('plex') and media_server_engine.client('plex').server:
_ab = getattr(media_server_engine.client('plex').server, '_baseurl', '') or ''
_at = getattr(media_server_engine.client('plex').server, '_token', '') or ''
if not _ab:
_pc = config_manager.get_plex_config()
_ab = (_pc.get('base_url', '') or '').rstrip('/')
@ -18364,10 +18364,10 @@ def server_playlist_replace_track(playlist_id):
active_server = config_manager.get_active_media_server()
if active_server == 'plex' and plex_client:
if active_server == 'plex' and media_server_engine.client('plex'):
# Use raw Plex API - fetch playlist directly
try:
raw_playlist = plex_client.server.playlist(playlist_name)
raw_playlist = media_server_engine.client('plex').server.playlist(playlist_name)
except Exception:
return jsonify({"success": False, "error": "Playlist not found on server"}), 404
@ -18376,7 +18376,7 @@ def server_playlist_replace_track(playlist_id):
replaced = False
for item in raw_playlist.items():
if str(item.ratingKey) == str(old_track_id) and not replaced:
new_item = plex_client.server.fetchItem(int(new_track_id))
new_item = media_server_engine.client('plex').server.fetchItem(int(new_track_id))
if new_item:
new_tracks.append(new_item)
replaced = True
@ -18389,13 +18389,13 @@ def server_playlist_replace_track(playlist_id):
# Delete old and recreate directly (avoid update_playlist's backup logic)
raw_playlist.delete()
from plexapi.playlist import Playlist
new_pl = Playlist.create(plex_client.server, playlist_name, items=new_tracks)
new_pl = Playlist.create(media_server_engine.client('plex').server, playlist_name, items=new_tracks)
return jsonify({"success": True, "message": "Track replaced", "new_playlist_id": str(new_pl.ratingKey)})
else:
return jsonify({"success": False, "error": "Old track not found in playlist"}), 404
elif active_server == 'jellyfin' and jellyfin_client:
current_tracks = jellyfin_client.get_playlist_tracks(playlist_id)
elif active_server == 'jellyfin' and media_server_engine.client('jellyfin'):
current_tracks = media_server_engine.client('jellyfin').get_playlist_tracks(playlist_id)
new_track_ids = []
replaced = False
for t in (current_tracks or []):
@ -18408,12 +18408,12 @@ def server_playlist_replace_track(playlist_id):
if replaced:
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in new_track_ids]
jellyfin_client.update_playlist(playlist_name, new_track_objs)
media_server_engine.client('jellyfin').update_playlist(playlist_name, new_track_objs)
return jsonify({"success": True, "message": "Track replaced"})
return jsonify({"success": False, "error": "Old track not found"}), 404
elif active_server == 'navidrome' and navidrome_client:
current_tracks = navidrome_client.get_playlist_tracks(playlist_id)
elif active_server == 'navidrome' and media_server_engine.client('navidrome'):
current_tracks = media_server_engine.client('navidrome').get_playlist_tracks(playlist_id)
new_track_ids = []
replaced = False
for t in (current_tracks or []):
@ -18426,7 +18426,7 @@ def server_playlist_replace_track(playlist_id):
if replaced:
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in new_track_ids]
navidrome_client.create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
media_server_engine.client('navidrome').create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
return jsonify({"success": True, "message": "Track replaced"})
return jsonify({"success": False, "error": "Old track not found"}), 404
@ -18452,12 +18452,12 @@ def server_playlist_add_track(playlist_id):
active_server = config_manager.get_active_media_server()
if active_server == 'plex' and plex_client:
if active_server == 'plex' and media_server_engine.client('plex'):
try:
raw_playlist = plex_client.server.playlist(playlist_name)
raw_playlist = media_server_engine.client('plex').server.playlist(playlist_name)
except Exception:
return jsonify({"success": False, "error": "Playlist not found"}), 404
new_item = plex_client.server.fetchItem(int(track_id))
new_item = media_server_engine.client('plex').server.fetchItem(int(track_id))
if not new_item:
return jsonify({"success": False, "error": "Track not found on server"}), 404
@ -18484,22 +18484,22 @@ def server_playlist_add_track(playlist_id):
logger.info(f"[ServerPlaylist] Added track to playlist, playlist ID: {new_id}")
return jsonify({"success": True, "message": "Track added", "new_playlist_id": new_id})
elif active_server == 'jellyfin' and jellyfin_client:
current_tracks = jellyfin_client.get_playlist_tracks(playlist_id) or []
elif active_server == 'jellyfin' and media_server_engine.client('jellyfin'):
current_tracks = media_server_engine.client('jellyfin').get_playlist_tracks(playlist_id) or []
track_ids = [str(t.ratingKey) for t in current_tracks]
pos = max(0, min(int(position), len(track_ids))) if position is not None else len(track_ids)
track_ids.insert(pos, track_id)
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in track_ids]
jellyfin_client.update_playlist(playlist_name, new_track_objs)
media_server_engine.client('jellyfin').update_playlist(playlist_name, new_track_objs)
return jsonify({"success": True, "message": "Track added"})
elif active_server == 'navidrome' and navidrome_client:
current_tracks = navidrome_client.get_playlist_tracks(playlist_id) or []
elif active_server == 'navidrome' and media_server_engine.client('navidrome'):
current_tracks = media_server_engine.client('navidrome').get_playlist_tracks(playlist_id) or []
track_ids = [str(t.ratingKey) for t in current_tracks]
pos = max(0, min(int(position), len(track_ids))) if position is not None else len(track_ids)
track_ids.insert(pos, track_id)
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in track_ids]
navidrome_client.create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
media_server_engine.client('navidrome').create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
return jsonify({"success": True, "message": "Track added"})
return jsonify({"success": False, "error": f"Unsupported server: {active_server}"}), 400
@ -18523,9 +18523,9 @@ def server_playlist_remove_track(playlist_id):
active_server = config_manager.get_active_media_server()
if active_server == 'plex' and plex_client:
if active_server == 'plex' and media_server_engine.client('plex'):
try:
raw_playlist = plex_client.server.playlist(playlist_name)
raw_playlist = media_server_engine.client('plex').server.playlist(playlist_name)
except Exception:
return jsonify({"success": False, "error": "Playlist not found"}), 404
@ -18537,26 +18537,26 @@ def server_playlist_remove_track(playlist_id):
raw_playlist.delete()
if new_items:
from plexapi.playlist import Playlist
new_pl = Playlist.create(plex_client.server, playlist_name, items=new_items)
new_pl = Playlist.create(media_server_engine.client('plex').server, playlist_name, items=new_items)
return jsonify({"success": True, "message": "Track removed", "new_playlist_id": str(new_pl.ratingKey)})
return jsonify({"success": True, "message": "Track removed (playlist now empty)"})
elif active_server == 'jellyfin' and jellyfin_client:
current_tracks = jellyfin_client.get_playlist_tracks(playlist_id) or []
elif active_server == 'jellyfin' and media_server_engine.client('jellyfin'):
current_tracks = media_server_engine.client('jellyfin').get_playlist_tracks(playlist_id) or []
new_ids = [str(t.ratingKey) for t in current_tracks if str(t.ratingKey) != str(remove_track_id)]
if len(new_ids) == len(current_tracks):
return jsonify({"success": False, "error": "Track not found in playlist"}), 404
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in new_ids]
jellyfin_client.update_playlist(playlist_name, new_track_objs)
media_server_engine.client('jellyfin').update_playlist(playlist_name, new_track_objs)
return jsonify({"success": True, "message": "Track removed"})
elif active_server == 'navidrome' and navidrome_client:
current_tracks = navidrome_client.get_playlist_tracks(playlist_id) or []
elif active_server == 'navidrome' and media_server_engine.client('navidrome'):
current_tracks = media_server_engine.client('navidrome').get_playlist_tracks(playlist_id) or []
new_ids = [str(t.ratingKey) for t in current_tracks if str(t.ratingKey) != str(remove_track_id)]
if len(new_ids) == len(current_tracks):
return jsonify({"success": False, "error": "Track not found in playlist"}), 404
new_track_objs = [type('T', (), {'ratingKey': tid, 'title': ''})() for tid in new_ids]
navidrome_client.create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
media_server_engine.client('navidrome').create_playlist(playlist_name, new_track_objs, playlist_id=playlist_id)
return jsonify({"success": True, "message": "Track removed"})
return jsonify({"success": False, "error": f"Unsupported server: {active_server}"}), 400
@ -18580,9 +18580,9 @@ def library_search_tracks():
# Build thumb URL resolver for this server
_art_prefix = ''
_art_suffix = ''
if active_server == 'plex' and plex_client and plex_client.server:
_ab = getattr(plex_client.server, '_baseurl', '') or ''
_at = getattr(plex_client.server, '_token', '') or ''
if active_server == 'plex' and media_server_engine.client('plex') and media_server_engine.client('plex').server:
_ab = getattr(media_server_engine.client('plex').server, '_baseurl', '') or ''
_at = getattr(media_server_engine.client('plex').server, '_token', '') or ''
if not _ab:
_pc = config_manager.get_plex_config()
_ab = (_pc.get('base_url', '') or '').rstrip('/')
@ -23399,12 +23399,12 @@ def test_database_access():
# Test media clients
logger.info(" Media clients status:")
logger.info(f" plex_client: {plex_client is not None}")
if plex_client:
logger.info(f" plex_client.is_connected(): {plex_client.is_connected()}")
logger.info(f" jellyfin_client: {jellyfin_client is not None}")
if jellyfin_client:
logger.info(f" jellyfin_client.is_connected(): {jellyfin_client.is_connected()}")
logger.info(f" media_server_engine.client('plex'): {media_server_engine.client('plex') is not None}")
if media_server_engine.client('plex'):
logger.info(f" media_server_engine.client('plex').is_connected(): {media_server_engine.client('plex').is_connected()}")
logger.info(f" media_server_engine.client('jellyfin'): {media_server_engine.client('jellyfin') is not None}")
if media_server_engine.client('jellyfin'):
logger.info(f" media_server_engine.client('jellyfin').is_connected(): {media_server_engine.client('jellyfin').is_connected()}")
return jsonify({
"success": True,
@ -23413,8 +23413,8 @@ def test_database_access():
"database_initialized": db is not None,
"database_stats": stats,
"active_server": active_server,
"plex_connected": plex_client.is_connected() if plex_client else False,
"jellyfin_connected": jellyfin_client.is_connected() if jellyfin_client else False,
"plex_connected": media_server_engine.client('plex').is_connected() if media_server_engine.client('plex') else False,
"jellyfin_connected": media_server_engine.client('jellyfin').is_connected() if media_server_engine.client('jellyfin') else False,
}
})
@ -29133,17 +29133,17 @@ def start_metadata_update():
# Get appropriate media client - Support all three servers
if active_server == "jellyfin":
media_client = jellyfin_client
media_client = media_server_engine.client('jellyfin')
if not media_client:
add_activity_item("", "Metadata Update", "Jellyfin client not available", "Now")
return jsonify({"success": False, "error": "Jellyfin client not available"}), 400
elif active_server == "navidrome":
media_client = navidrome_client
media_client = media_server_engine.client('navidrome')
if not media_client:
add_activity_item("", "Metadata Update", "Navidrome client not available", "Now")
return jsonify({"success": False, "error": "Navidrome client not available"}), 400
else: # plex
media_client = plex_client
media_client = media_server_engine.client('plex')
if not media_client:
add_activity_item("", "Metadata Update", "Plex client not available", "Now")
return jsonify({"success": False, "error": "Plex client not available"}), 400

Loading…
Cancel
Save