diff --git a/ui/pages/artists.py b/ui/pages/artists.py index 4a25b4c4..3ab28c26 100644 --- a/ui/pages/artists.py +++ b/ui/pages/artists.py @@ -1816,14 +1816,15 @@ class DownloadMissingAlbumTracksModal(QDialog): """Enhanced modal for downloading missing album tracks with live progress tracking""" process_finished = pyqtSignal() - def __init__(self, album, album_card, parent_page, downloads_page, plex_client): + def __init__(self, album, album_card, parent_page, downloads_page, media_client, server_type): super().__init__(parent_page) self.album = album self.album_card = album_card self.parent_page = parent_page self.parent_artists_page = parent_page # Reference to artists page for scan manager self.downloads_page = downloads_page - self.plex_client = plex_client + self.media_client = media_client + self.server_type = server_type self.matching_engine = MusicMatchingEngine() self.wishlist_service = get_wishlist_service() @@ -2395,9 +2396,9 @@ class DownloadMissingAlbumTracksModal(QDialog): self.start_plex_analysis() def start_plex_analysis(self): - """Start database analysis for album tracks (previously Plex analysis)""" + """Start database analysis for album tracks (server-aware)""" from ui.pages.sync import PlaylistTrackAnalysisWorker - worker = PlaylistTrackAnalysisWorker(self.album.tracks, self.plex_client) + worker = PlaylistTrackAnalysisWorker(self.album.tracks, self.media_client) worker.signals.analysis_started.connect(self.on_analysis_started) worker.signals.track_analyzed.connect(self.on_track_analyzed) worker.signals.analysis_completed.connect(self.on_analysis_completed) @@ -3291,7 +3292,7 @@ class ArtistsPage(QWidget): # Create worker for incremental update only self._auto_database_worker = DatabaseUpdateWorker( - self.plex_client, + self.media_client, "database/music_library.db", full_refresh=False # Always incremental for automatic updates ) @@ -3338,12 +3339,27 @@ class ArtistsPage(QWidget): def setup_clients(self): """Initialize client connections""" try: + from config.settings import config_manager + self.spotify_client = SpotifyClient() self.plex_client = PlexClient() + + # Add Jellyfin client for multi-server support + from core.jellyfin_client import JellyfinClient + self.jellyfin_client = JellyfinClient() + + # Set up unified media client based on active server + active_server = config_manager.get_active_media_server() + if active_server == "plex": + self.media_client = self.plex_client + self.server_type = "plex" + else: # jellyfin + self.media_client = self.jellyfin_client + self.server_type = "jellyfin" + self.soulseek_client = SoulseekClient() # --- FIX: Ensure the soulseek_client uses the download path from config --- - from config.settings import config_manager download_path = config_manager.get('soulseek.download_path') if download_path and hasattr(self.soulseek_client, 'download_path'): self.soulseek_client.download_path = download_path @@ -4332,7 +4348,7 @@ class ArtistsPage(QWidget): QMessageBox.critical(self, "Error", "Downloads page is not connected. Cannot start download.") return - if not self.plex_client: + if not self.media_client: QMessageBox.critical(self, "Error", "Music database is not available. Cannot verify existing tracks.") return @@ -4414,12 +4430,28 @@ class ArtistsPage(QWidget): album_with_tracks.tracks = tracks # Add tracks attribute dynamically # Create and show the new sophisticated modal + # Get active server and media client + from config.settings import config_manager + active_server = config_manager.get_active_media_server() + + if active_server == "jellyfin": + media_client = getattr(self, 'jellyfin_client', None) + if not media_client: + QMessageBox.critical(self, "Error", "Jellyfin client not available") + return + else: + media_client = self.plex_client + if not media_client: + QMessageBox.critical(self, "Error", "Plex client not available") + return + modal = DownloadMissingAlbumTracksModal( album=album_with_tracks, # Use the album with tracks album_card=album_card, parent_page=self, downloads_page=self.downloads_page, - plex_client=self.plex_client + media_client=media_client, + server_type=active_server ) # Store the session for resumption diff --git a/ui/pages/sync.py b/ui/pages/sync.py index a22e0245..9398eba4 100644 --- a/ui/pages/sync.py +++ b/ui/pages/sync.py @@ -521,12 +521,13 @@ class PlaylistTrackAnalysisWorkerSignals(QObject): analysis_failed = pyqtSignal(str) # error_message class PlaylistTrackAnalysisWorker(QRunnable): - """Background worker to analyze playlist tracks against Plex library""" + """Background worker to analyze playlist tracks against media library""" - def __init__(self, playlist_tracks, plex_client): + def __init__(self, playlist_tracks, media_client, server_type="plex"): super().__init__() self.playlist_tracks = playlist_tracks - self.plex_client = plex_client + self.media_client = media_client # Can be plex_client or jellyfin_client + self.server_type = server_type self.signals = PlaylistTrackAnalysisWorkerSignals() self._cancelled = False # Instantiate the matching engine once per worker for efficiency @@ -545,14 +546,14 @@ class PlaylistTrackAnalysisWorker(QRunnable): self.signals.analysis_started.emit(len(self.playlist_tracks)) results = [] - # Check if Plex is connected - plex_connected = False + # Check if media server is connected + server_connected = False try: - if self.plex_client: - plex_connected = self.plex_client.is_connected() + if self.media_client: + server_connected = self.media_client.is_connected() except Exception as e: - print(f"Plex connection check failed: {e}") - plex_connected = False + print(f"{self.server_type.title()} connection check failed: {e}") + server_connected = False for i, track in enumerate(self.playlist_tracks): if self._cancelled: @@ -563,17 +564,17 @@ class PlaylistTrackAnalysisWorker(QRunnable): exists_in_plex=False ) - if plex_connected: - # Check if track exists in Plex + if server_connected: + # Check if track exists in media server try: - plex_match, confidence = self._check_track_in_plex(track) + match, confidence = self._check_track_in_library(track) # Use the 0.8 confidence threshold - if plex_match and confidence >= 0.8: - result.exists_in_plex = True - result.plex_match = plex_match + if match and confidence >= 0.8: + result.exists_in_plex = True # Keep existing field name for compatibility + result.plex_match = match # Keep existing field name for compatibility result.confidence = confidence except Exception as e: - result.error_message = f"Plex check failed: {str(e)}" + result.error_message = f"{self.server_type.title()} check failed: {str(e)}" results.append(result) self.signals.track_analyzed.emit(i + 1, result) @@ -587,11 +588,11 @@ class PlaylistTrackAnalysisWorker(QRunnable): traceback.print_exc() self.signals.analysis_failed.emit(str(e)) - def _check_track_in_plex(self, spotify_track): + def _check_track_in_library(self, spotify_track): """ Check if a Spotify track exists in the database by searching for each artist and stopping as soon as a confident match is found. - Now uses local database instead of Plex API for much faster performance. + Now uses local database instead of media server API for much faster performance. """ try: original_title = spotify_track.name @@ -1715,14 +1716,24 @@ class PlaylistDetailsModal(QDialog): self.start_track_analysis() # Show analysis started message + from config.settings import config_manager + active_server = config_manager.get_active_media_server() + server_name = active_server.title() QMessageBox.information(self, "Analysis Started", - f"Starting analysis of {track_count} tracks.\nChecking Plex library for existing tracks...") + f"Starting analysis of {track_count} tracks.\nChecking {server_name} library for existing tracks...") def start_track_analysis(self): - """Start background track analysis against Plex library""" + """Start background track analysis against media library""" # Create analysis worker - plex_client = getattr(self.parent_page, 'plex_client', None) - worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, plex_client) + from config.settings import config_manager + active_server = config_manager.get_active_media_server() + + if active_server == "plex": + media_client = getattr(self.parent_page, 'plex_client', None) + else: # jellyfin + media_client = getattr(self.parent_page, 'jellyfin_client', None) + + worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, media_client, active_server) # Connect signals worker.signals.analysis_started.connect(self.on_analysis_started) @@ -6699,9 +6710,16 @@ class DownloadMissingTracksModal(QDialog): def start_plex_analysis(self): - """Start Plex analysis using existing worker""" - plex_client = getattr(self.parent_page, 'plex_client', None) - worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, plex_client) + """Start media server analysis using existing worker""" + from config.settings import config_manager + active_server = config_manager.get_active_media_server() + + if active_server == "plex": + media_client = getattr(self.parent_page, 'plex_client', None) + else: # jellyfin + media_client = getattr(self.parent_page, 'jellyfin_client', None) + + worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, media_client, active_server) worker.signals.analysis_started.connect(self.on_analysis_started) worker.signals.track_analyzed.connect(self.on_track_analyzed) worker.signals.analysis_completed.connect(self.on_analysis_completed)