@ -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