bug fix
This commit is contained in:
parent
ceeb4c22dc
commit
7c84b687fb
2 changed files with 83 additions and 33 deletions
|
|
@ -1816,14 +1816,15 @@ class DownloadMissingAlbumTracksModal(QDialog):
|
||||||
"""Enhanced modal for downloading missing album tracks with live progress tracking"""
|
"""Enhanced modal for downloading missing album tracks with live progress tracking"""
|
||||||
process_finished = pyqtSignal()
|
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)
|
super().__init__(parent_page)
|
||||||
self.album = album
|
self.album = album
|
||||||
self.album_card = album_card
|
self.album_card = album_card
|
||||||
self.parent_page = parent_page
|
self.parent_page = parent_page
|
||||||
self.parent_artists_page = parent_page # Reference to artists page for scan manager
|
self.parent_artists_page = parent_page # Reference to artists page for scan manager
|
||||||
self.downloads_page = downloads_page
|
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.matching_engine = MusicMatchingEngine()
|
||||||
self.wishlist_service = get_wishlist_service()
|
self.wishlist_service = get_wishlist_service()
|
||||||
|
|
||||||
|
|
@ -2395,9 +2396,9 @@ class DownloadMissingAlbumTracksModal(QDialog):
|
||||||
self.start_plex_analysis()
|
self.start_plex_analysis()
|
||||||
|
|
||||||
def start_plex_analysis(self):
|
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
|
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.analysis_started.connect(self.on_analysis_started)
|
||||||
worker.signals.track_analyzed.connect(self.on_track_analyzed)
|
worker.signals.track_analyzed.connect(self.on_track_analyzed)
|
||||||
worker.signals.analysis_completed.connect(self.on_analysis_completed)
|
worker.signals.analysis_completed.connect(self.on_analysis_completed)
|
||||||
|
|
@ -3291,7 +3292,7 @@ class ArtistsPage(QWidget):
|
||||||
|
|
||||||
# Create worker for incremental update only
|
# Create worker for incremental update only
|
||||||
self._auto_database_worker = DatabaseUpdateWorker(
|
self._auto_database_worker = DatabaseUpdateWorker(
|
||||||
self.plex_client,
|
self.media_client,
|
||||||
"database/music_library.db",
|
"database/music_library.db",
|
||||||
full_refresh=False # Always incremental for automatic updates
|
full_refresh=False # Always incremental for automatic updates
|
||||||
)
|
)
|
||||||
|
|
@ -3338,12 +3339,27 @@ class ArtistsPage(QWidget):
|
||||||
def setup_clients(self):
|
def setup_clients(self):
|
||||||
"""Initialize client connections"""
|
"""Initialize client connections"""
|
||||||
try:
|
try:
|
||||||
|
from config.settings import config_manager
|
||||||
|
|
||||||
self.spotify_client = SpotifyClient()
|
self.spotify_client = SpotifyClient()
|
||||||
self.plex_client = PlexClient()
|
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()
|
self.soulseek_client = SoulseekClient()
|
||||||
|
|
||||||
# --- FIX: Ensure the soulseek_client uses the download path from config ---
|
# --- 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')
|
download_path = config_manager.get('soulseek.download_path')
|
||||||
if download_path and hasattr(self.soulseek_client, 'download_path'):
|
if download_path and hasattr(self.soulseek_client, 'download_path'):
|
||||||
self.soulseek_client.download_path = 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.")
|
QMessageBox.critical(self, "Error", "Downloads page is not connected. Cannot start download.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.plex_client:
|
if not self.media_client:
|
||||||
QMessageBox.critical(self, "Error", "Music database is not available. Cannot verify existing tracks.")
|
QMessageBox.critical(self, "Error", "Music database is not available. Cannot verify existing tracks.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -4414,12 +4430,28 @@ class ArtistsPage(QWidget):
|
||||||
album_with_tracks.tracks = tracks # Add tracks attribute dynamically
|
album_with_tracks.tracks = tracks # Add tracks attribute dynamically
|
||||||
|
|
||||||
# Create and show the new sophisticated modal
|
# 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(
|
modal = DownloadMissingAlbumTracksModal(
|
||||||
album=album_with_tracks, # Use the album with tracks
|
album=album_with_tracks, # Use the album with tracks
|
||||||
album_card=album_card,
|
album_card=album_card,
|
||||||
parent_page=self,
|
parent_page=self,
|
||||||
downloads_page=self.downloads_page,
|
downloads_page=self.downloads_page,
|
||||||
plex_client=self.plex_client
|
media_client=media_client,
|
||||||
|
server_type=active_server
|
||||||
)
|
)
|
||||||
|
|
||||||
# Store the session for resumption
|
# Store the session for resumption
|
||||||
|
|
|
||||||
|
|
@ -521,12 +521,13 @@ class PlaylistTrackAnalysisWorkerSignals(QObject):
|
||||||
analysis_failed = pyqtSignal(str) # error_message
|
analysis_failed = pyqtSignal(str) # error_message
|
||||||
|
|
||||||
class PlaylistTrackAnalysisWorker(QRunnable):
|
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__()
|
super().__init__()
|
||||||
self.playlist_tracks = playlist_tracks
|
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.signals = PlaylistTrackAnalysisWorkerSignals()
|
||||||
self._cancelled = False
|
self._cancelled = False
|
||||||
# Instantiate the matching engine once per worker for efficiency
|
# 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))
|
self.signals.analysis_started.emit(len(self.playlist_tracks))
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
# Check if Plex is connected
|
# Check if media server is connected
|
||||||
plex_connected = False
|
server_connected = False
|
||||||
try:
|
try:
|
||||||
if self.plex_client:
|
if self.media_client:
|
||||||
plex_connected = self.plex_client.is_connected()
|
server_connected = self.media_client.is_connected()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Plex connection check failed: {e}")
|
print(f"{self.server_type.title()} connection check failed: {e}")
|
||||||
plex_connected = False
|
server_connected = False
|
||||||
|
|
||||||
for i, track in enumerate(self.playlist_tracks):
|
for i, track in enumerate(self.playlist_tracks):
|
||||||
if self._cancelled:
|
if self._cancelled:
|
||||||
|
|
@ -563,17 +564,17 @@ class PlaylistTrackAnalysisWorker(QRunnable):
|
||||||
exists_in_plex=False
|
exists_in_plex=False
|
||||||
)
|
)
|
||||||
|
|
||||||
if plex_connected:
|
if server_connected:
|
||||||
# Check if track exists in Plex
|
# Check if track exists in media server
|
||||||
try:
|
try:
|
||||||
plex_match, confidence = self._check_track_in_plex(track)
|
match, confidence = self._check_track_in_library(track)
|
||||||
# Use the 0.8 confidence threshold
|
# Use the 0.8 confidence threshold
|
||||||
if plex_match and confidence >= 0.8:
|
if match and confidence >= 0.8:
|
||||||
result.exists_in_plex = True
|
result.exists_in_plex = True # Keep existing field name for compatibility
|
||||||
result.plex_match = plex_match
|
result.plex_match = match # Keep existing field name for compatibility
|
||||||
result.confidence = confidence
|
result.confidence = confidence
|
||||||
except Exception as e:
|
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)
|
results.append(result)
|
||||||
self.signals.track_analyzed.emit(i + 1, result)
|
self.signals.track_analyzed.emit(i + 1, result)
|
||||||
|
|
@ -587,11 +588,11 @@ class PlaylistTrackAnalysisWorker(QRunnable):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
self.signals.analysis_failed.emit(str(e))
|
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
|
Check if a Spotify track exists in the database by searching for each artist and
|
||||||
stopping as soon as a confident match is found.
|
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:
|
try:
|
||||||
original_title = spotify_track.name
|
original_title = spotify_track.name
|
||||||
|
|
@ -1715,14 +1716,24 @@ class PlaylistDetailsModal(QDialog):
|
||||||
self.start_track_analysis()
|
self.start_track_analysis()
|
||||||
|
|
||||||
# Show analysis started message
|
# 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",
|
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):
|
def start_track_analysis(self):
|
||||||
"""Start background track analysis against Plex library"""
|
"""Start background track analysis against media library"""
|
||||||
# Create analysis worker
|
# Create analysis worker
|
||||||
plex_client = getattr(self.parent_page, 'plex_client', None)
|
from config.settings import config_manager
|
||||||
worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, plex_client)
|
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
|
# Connect signals
|
||||||
worker.signals.analysis_started.connect(self.on_analysis_started)
|
worker.signals.analysis_started.connect(self.on_analysis_started)
|
||||||
|
|
@ -6699,9 +6710,16 @@ class DownloadMissingTracksModal(QDialog):
|
||||||
|
|
||||||
|
|
||||||
def start_plex_analysis(self):
|
def start_plex_analysis(self):
|
||||||
"""Start Plex analysis using existing worker"""
|
"""Start media server analysis using existing worker"""
|
||||||
plex_client = getattr(self.parent_page, 'plex_client', None)
|
from config.settings import config_manager
|
||||||
worker = PlaylistTrackAnalysisWorker(self.playlist.tracks, plex_client)
|
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.analysis_started.connect(self.on_analysis_started)
|
||||||
worker.signals.track_analyzed.connect(self.on_track_analyzed)
|
worker.signals.track_analyzed.connect(self.on_track_analyzed)
|
||||||
worker.signals.analysis_completed.connect(self.on_analysis_completed)
|
worker.signals.analysis_completed.connect(self.on_analysis_completed)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue