good
This commit is contained in:
parent
f456f4a4c2
commit
52695fd6a2
7 changed files with 11734 additions and 18 deletions
|
|
@ -1 +1 @@
|
||||||
{"access_token": "BQAGFYuFGcSZ2MXk4qaE7u41ZhYZ2_6EBIrkMAQTBHWVapuPZDvR-laSVBFyPp96cY8-eWl2v0mYJDd7A2MCzXb1hZ8XY3973NxpJOLTlI8MtTwl2IbV5ZPOkA21eVeJGdWAlF8mmU0NPqcBVh0KUzVtGGvaYO3foV2bdgd2gsBnUJYrAGQukwoZ_LVLEF-grSAqIyWE4vLGVawUOnZNTlT0JQtxi4f5gTS-GdJtqqHU-1bjqCkcXoer-p-ywrH_", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753738591, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}
|
{"access_token": "BQDOhKfFATvb-8-rw278Xzc-T-QgPJ5_7mWFHT4yw83y2c5yvmDDQ8qdkKuiFc-Hfc8V7L6o_8w9d5Vl9TPuek9pxE-PNeNPwxsRn9CVScttd2_XEuxnR-ag53yqrMP4rSaUZnXT5pd1tqizay2aOpmdfV89BTg7-Vj3SARGgofrhBbJqO4hNZY5EqVGpWpDyzJCUeG4W7jvLC62eO8qFVpnbrqNdRKGMeZ6FfCdiVZfjrxlPv9a-LaUYeazk3aR", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1753742887, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}
|
||||||
11658
logs/app.log
11658
logs/app.log
File diff suppressed because it is too large
Load diff
5
main.py
5
main.py
|
|
@ -176,6 +176,11 @@ class MainWindow(QMainWindow):
|
||||||
self.dashboard_page.add_activity_item
|
self.dashboard_page.add_activity_item
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Connect download activities to dashboard
|
||||||
|
self.downloads_page.download_activity.connect(
|
||||||
|
self.dashboard_page.add_activity_item
|
||||||
|
)
|
||||||
|
|
||||||
self.stacked_widget.addWidget(self.dashboard_page)
|
self.stacked_widget.addWidget(self.dashboard_page)
|
||||||
self.stacked_widget.addWidget(self.sync_page)
|
self.stacked_widget.addWidget(self.sync_page)
|
||||||
self.stacked_widget.addWidget(self.downloads_page)
|
self.stacked_widget.addWidget(self.downloads_page)
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -90,12 +90,12 @@ class DashboardDataProvider(QObject):
|
||||||
def set_app_start_time(self, start_time):
|
def set_app_start_time(self, start_time):
|
||||||
self.app_start_time = start_time
|
self.app_start_time = start_time
|
||||||
|
|
||||||
def increment_completed_downloads(self):
|
def increment_completed_downloads(self, title="Unknown Track", artist="Unknown Artist"):
|
||||||
"""Increment the session completed downloads counter"""
|
"""Increment the session completed downloads counter"""
|
||||||
self.session_completed_downloads += 1
|
self.session_completed_downloads += 1
|
||||||
|
|
||||||
# Emit signal for activity feed
|
# Emit signal for activity feed with specific track info
|
||||||
self.activity_item_added.emit("📥", "Download Complete", "File downloaded successfully", "Now")
|
self.activity_item_added.emit("📥", "Download Complete", f"'{title}' by {artist}", "Now")
|
||||||
|
|
||||||
def update_service_status(self, service: str, connected: bool, response_time: float = 0.0, error: str = ""):
|
def update_service_status(self, service: str, connected: bool, response_time: float = 0.0, error: str = ""):
|
||||||
if service in self.service_status:
|
if service in self.service_status:
|
||||||
|
|
|
||||||
|
|
@ -4687,7 +4687,7 @@ class TabbedDownloadManager(QTabWidget):
|
||||||
while parent_page and not hasattr(parent_page, 'download_session_completed'):
|
while parent_page and not hasattr(parent_page, 'download_session_completed'):
|
||||||
parent_page = parent_page.parent()
|
parent_page = parent_page.parent()
|
||||||
if parent_page and hasattr(parent_page, 'download_session_completed'):
|
if parent_page and hasattr(parent_page, 'download_session_completed'):
|
||||||
parent_page.download_session_completed.emit()
|
parent_page.download_session_completed.emit(download_item.title, download_item.artist)
|
||||||
|
|
||||||
# Performance monitoring
|
# Performance monitoring
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
|
|
@ -4802,8 +4802,11 @@ class DownloadsPage(QWidget):
|
||||||
track_loading_finished = pyqtSignal(object) # Track result object when streaming completes
|
track_loading_finished = pyqtSignal(object) # Track result object when streaming completes
|
||||||
track_loading_progress = pyqtSignal(float, object) # Progress percentage (0-100), track result object
|
track_loading_progress = pyqtSignal(float, object) # Progress percentage (0-100), track result object
|
||||||
|
|
||||||
# Signal for dashboard stats tracking
|
# Signal for dashboard stats tracking
|
||||||
download_session_completed = pyqtSignal() # Emitted when a download completes (for session tracking)
|
download_session_completed = pyqtSignal(str, str) # Emitted when a download completes (title, artist)
|
||||||
|
|
||||||
|
# Signals for dashboard activity tracking
|
||||||
|
download_activity = pyqtSignal(str, str, str, str) # icon, title, subtitle, time
|
||||||
|
|
||||||
# Signal for clear completed downloads completion (thread-safe communication)
|
# Signal for clear completed downloads completion (thread-safe communication)
|
||||||
clear_completed_finished = pyqtSignal(bool, object) # backend_success, ui_callback
|
clear_completed_finished = pyqtSignal(bool, object) # backend_success, ui_callback
|
||||||
|
|
@ -6321,6 +6324,9 @@ class DownloadsPage(QWidget):
|
||||||
self.search_btn.setEnabled(False)
|
self.search_btn.setEnabled(False)
|
||||||
self.update_search_status(f"Searching for '{query}'... Results will appear as they are found", "#1db954")
|
self.update_search_status(f"Searching for '{query}'... Results will appear as they are found", "#1db954")
|
||||||
|
|
||||||
|
# Emit activity signal for search start
|
||||||
|
self.download_activity.emit("🔍", "Search Started", f"Searching for '{query}'", "Now")
|
||||||
|
|
||||||
# Show loading animations
|
# Show loading animations
|
||||||
self.start_search_animations()
|
self.start_search_animations()
|
||||||
|
|
||||||
|
|
@ -6566,6 +6572,10 @@ class DownloadsPage(QWidget):
|
||||||
# Show filter controls when we have results
|
# Show filter controls when we have results
|
||||||
self.filter_container.setVisible(True)
|
self.filter_container.setVisible(True)
|
||||||
|
|
||||||
|
# Emit activity signal for search completion
|
||||||
|
search_query = self.search_input.text().strip()
|
||||||
|
self.download_activity.emit("✅", "Search Complete", f"Found {total_results} results for '{search_query}'", "Now")
|
||||||
|
|
||||||
# Update status based on whether there are more results to load
|
# Update status based on whether there are more results to load
|
||||||
if self.displayed_results < total_results:
|
if self.displayed_results < total_results:
|
||||||
remaining = total_results - self.displayed_results
|
remaining = total_results - self.displayed_results
|
||||||
|
|
@ -6712,18 +6722,32 @@ class DownloadsPage(QWidget):
|
||||||
if '.' in name_without_ext:
|
if '.' in name_without_ext:
|
||||||
name_without_ext = '.'.join(name_without_ext.split('.')[:-1])
|
name_without_ext = '.'.join(name_without_ext.split('.')[:-1])
|
||||||
|
|
||||||
# Remove track number prefix
|
# Remove track number prefix - handle multiple formats
|
||||||
import re
|
import re
|
||||||
track_number_match = re.match(r'^(\d+)\.\s*(.+)', name_without_ext)
|
name_without_track_num = name_without_ext
|
||||||
if track_number_match:
|
|
||||||
name_without_track_num = track_number_match.group(2)
|
# Try different track number patterns
|
||||||
else:
|
track_patterns = [
|
||||||
name_without_track_num = name_without_ext
|
r'^(\d+)\.\s*(.+)', # "06. Artist - Track"
|
||||||
|
r'^(\d+)\s*-\s*(.+)', # "06 - Artist - Track"
|
||||||
|
r'^(\d+)\s+(.+)' # "06 Artist - Track"
|
||||||
|
]
|
||||||
|
|
||||||
|
for pattern in track_patterns:
|
||||||
|
match = re.match(pattern, name_without_ext)
|
||||||
|
if match:
|
||||||
|
name_without_track_num = match.group(2)
|
||||||
|
break
|
||||||
|
|
||||||
# Extract artist (first part before " - ")
|
# Extract artist (first part before " - ")
|
||||||
parts = name_without_track_num.split(' - ')
|
parts = name_without_track_num.split(' - ')
|
||||||
if len(parts) >= 2:
|
if len(parts) >= 2:
|
||||||
|
# First part is artist, second part is track title
|
||||||
artist = parts[0].strip()
|
artist = parts[0].strip()
|
||||||
|
# Verify this doesn't look like a track number
|
||||||
|
if re.match(r'^\d+$', artist.strip()):
|
||||||
|
# If first part is just a number, use username as fallback
|
||||||
|
artist = search_result.username
|
||||||
else:
|
else:
|
||||||
artist = search_result.username
|
artist = search_result.username
|
||||||
|
|
||||||
|
|
@ -6773,6 +6797,9 @@ class DownloadsPage(QWidget):
|
||||||
|
|
||||||
print(f"[DEBUG] Created download item with album context: album='{album_name}', track_number={track_number}")
|
print(f"[DEBUG] Created download item with album context: album='{album_name}', track_number={track_number}")
|
||||||
|
|
||||||
|
# Emit activity signal for download start
|
||||||
|
self.download_activity.emit("📥", "Download Started", f"'{title}' by {artist}", "Now")
|
||||||
|
|
||||||
# Create and start download thread
|
# Create and start download thread
|
||||||
download_thread = DownloadThread(self.soulseek_client, search_result, download_item)
|
download_thread = DownloadThread(self.soulseek_client, search_result, download_item)
|
||||||
download_thread.download_completed.connect(self.on_download_completed, Qt.ConnectionType.QueuedConnection)
|
download_thread.download_completed.connect(self.on_download_completed, Qt.ConnectionType.QueuedConnection)
|
||||||
|
|
@ -6974,15 +7001,28 @@ class DownloadsPage(QWidget):
|
||||||
name_without_ext = '.'.join(name_without_ext.split('.')[:-1])
|
name_without_ext = '.'.join(name_without_ext.split('.')[:-1])
|
||||||
|
|
||||||
import re
|
import re
|
||||||
track_number_match = re.match(r'^(\d+)\.\s*(.+)', name_without_ext)
|
name_without_track_num = name_without_ext
|
||||||
if track_number_match:
|
|
||||||
name_without_track_num = track_number_match.group(2)
|
# Try different track number patterns
|
||||||
else:
|
track_patterns = [
|
||||||
name_without_track_num = name_without_ext
|
r'^(\d+)\.\s*(.+)', # "06. Artist - Track"
|
||||||
|
r'^(\d+)\s*-\s*(.+)', # "06 - Artist - Track"
|
||||||
|
r'^(\d+)\s+(.+)' # "06 Artist - Track"
|
||||||
|
]
|
||||||
|
|
||||||
|
for pattern in track_patterns:
|
||||||
|
match = re.match(pattern, name_without_ext)
|
||||||
|
if match:
|
||||||
|
name_without_track_num = match.group(2)
|
||||||
|
break
|
||||||
|
|
||||||
parts = name_without_track_num.split(' - ')
|
parts = name_without_track_num.split(' - ')
|
||||||
if len(parts) >= 2:
|
if len(parts) >= 2:
|
||||||
original_artist = parts[0].strip()
|
original_artist = parts[0].strip()
|
||||||
|
# Verify this doesn't look like a track number
|
||||||
|
if re.match(r'^\d+$', original_artist.strip()):
|
||||||
|
# If first part is just a number, use username as fallback
|
||||||
|
original_artist = search_result.username
|
||||||
else:
|
else:
|
||||||
original_artist = search_result.username
|
original_artist = search_result.username
|
||||||
|
|
||||||
|
|
@ -7031,6 +7071,9 @@ class DownloadsPage(QWidget):
|
||||||
download_item.matched_artist = artist
|
download_item.matched_artist = artist
|
||||||
print(f"✅ Matched artist '{artist.name}' assigned to download item '{download_item.title}'")
|
print(f"✅ Matched artist '{artist.name}' assigned to download item '{download_item.title}'")
|
||||||
|
|
||||||
|
# Emit activity signal for download start (with matched artist)
|
||||||
|
self.download_activity.emit("📥", "Download Started", f"'{title}' by {artist.name if artist else original_artist}", "Now")
|
||||||
|
|
||||||
# Start the download thread
|
# Start the download thread
|
||||||
download_thread = DownloadThread(self.soulseek_client, search_result, download_item)
|
download_thread = DownloadThread(self.soulseek_client, search_result, download_item)
|
||||||
download_thread.download_completed.connect(self.on_download_completed, Qt.ConnectionType.QueuedConnection)
|
download_thread.download_completed.connect(self.on_download_completed, Qt.ConnectionType.QueuedConnection)
|
||||||
|
|
@ -8967,6 +9010,10 @@ class DownloadsPage(QWidget):
|
||||||
# Update download item status to failed
|
# Update download item status to failed
|
||||||
download_item.status = "failed"
|
download_item.status = "failed"
|
||||||
download_item.progress = 0
|
download_item.progress = 0
|
||||||
|
|
||||||
|
# Emit activity signal for download failure
|
||||||
|
self.download_activity.emit("❌", "Download Failed", f"'{download_item.title}' - {error_msg}", "Now")
|
||||||
|
|
||||||
# Error logged to console for debugging
|
# Error logged to console for debugging
|
||||||
|
|
||||||
def on_download_progress(self, message, download_item):
|
def on_download_progress(self, message, download_item):
|
||||||
|
|
@ -9355,6 +9402,12 @@ class DownloadsPage(QWidget):
|
||||||
# Move to finished queue
|
# Move to finished queue
|
||||||
self.download_queue.move_to_finished(download_item)
|
self.download_queue.move_to_finished(download_item)
|
||||||
|
|
||||||
|
# Emit specific activity signal for failures
|
||||||
|
if new_status == 'failed':
|
||||||
|
self.download_activity.emit("❌", "Download Failed", f"'{download_item.title}' by {download_item.artist}", "Now")
|
||||||
|
elif new_status == 'cancelled':
|
||||||
|
self.download_activity.emit("⏹️", "Download Cancelled", f"'{download_item.title}' by {download_item.artist}", "Now")
|
||||||
|
|
||||||
# Cleanup API if needed
|
# Cleanup API if needed
|
||||||
if new_status in ['cancelled', 'failed'] and hasattr(download_item, 'download_id'):
|
if new_status in ['cancelled', 'failed'] and hasattr(download_item, 'download_id'):
|
||||||
self._schedule_api_cleanup_v2(download_item)
|
self._schedule_api_cleanup_v2(download_item)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue