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).
This commit is contained in:
parent
49f7679eef
commit
1bc5017592
1 changed files with 110 additions and 110 deletions
220
web_server.py
220
web_server.py
|
|
@ -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…
Reference in a new issue