happy right now

This commit is contained in:
Broque Thomas 2025-07-15 23:20:21 -07:00
parent 93994d5995
commit 48463f8eaf
4 changed files with 6922 additions and 28 deletions

View file

@ -1 +1 @@
{"access_token": "BQAMCHC8-xUmBuvLsfPGL-cTN8YH_moz_up1xx8fMIxqQTqSXlwo2R0samLLNnq6qM31CfLC_2XM7SkGjCxCSbGOUs0qaVDO3f2Dv7fbsFSuNmR3pFKfICDJdUCxjR3BA6jlJD_03emn8-mgVQx605QTFmNlK8uOTrwBAjaY_Pxww3XSLnpTm3coHDrc8astutR0MeEUlm9894AI3GXh-F0g7IDKdGHiKQhd2sVHgCm41Q355igboNTBMdAVkVGW", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1752637352, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"} {"access_token": "BQBnvqMpOwqMzo5WbMGTkdmXGAnz-XQH7yfzsmlMIOyjdT1HG9HS6x8XtEfZ65F90RTO948crkDprgcqdP7Ryh54wxWxK-b6bNB2K9InQOXeVHUEwCwaO7fQ3H-PMVGYr0EGXp_EhkEYn4l3H_ps6MWr2r4sPfPw5lTP8o4qvIjHe8AYttlffxA2exNMrN2S2Ed668PYyvCwu4b2THNXsBH73EJHXP55bwg0Mo35i9PjdGgdJs30MbKcFZfdfbOS", "token_type": "Bearer", "expires_in": 3600, "scope": "user-library-read user-read-private playlist-read-private playlist-read-collaborative user-read-email", "expires_at": 1752649260, "refresh_token": "AQDmfQkPCGObfJeTUIbW1hAAwhSqkuHRA3Qh2dqVYMRh0eCkFMQgPNJDDzF8y-BiaVbj80zePkK_XSfYH1aJutMtNbnsqRKWuxP31BTrMc7pdUdbE7Fma4oH8wpDUKdG3MM"}

File diff suppressed because it is too large Load diff

View file

@ -4453,12 +4453,9 @@ class TabbedDownloadManager(QTabWidget):
def move_to_finished(self, download_item): def move_to_finished(self, download_item):
"""Move a download item from active to finished queue""" """Move a download item from active to finished queue"""
print(f"[DEBUG] move_to_finished() called for '{download_item.title}' with status '{download_item.status}'")
print(f"[DEBUG] Finished queue currently has {len(self.finished_queue.download_items)} items")
if download_item in self.active_queue.download_items: if download_item in self.active_queue.download_items:
# Remove from active queue # Remove from active queue
print(f"[DEBUG] Removing '{download_item.title}' from active queue...")
self.active_queue.remove_download_item(download_item) self.active_queue.remove_download_item(download_item)
# Ensure completed downloads have 100% progress # Ensure completed downloads have 100% progress
@ -4468,7 +4465,6 @@ class TabbedDownloadManager(QTabWidget):
print(f"[DEBUG] Ensuring completed download '{download_item.title}' has 100% progress") print(f"[DEBUG] Ensuring completed download '{download_item.title}' has 100% progress")
# Add to finished queue # Add to finished queue
print(f"[DEBUG] Adding '{download_item.title}' to finished queue with status '{download_item.status}'...")
finished_item = self.finished_queue.add_download_item( finished_item = self.finished_queue.add_download_item(
title=download_item.title, title=download_item.title,
artist=download_item.artist, artist=download_item.artist,
@ -4481,33 +4477,42 @@ class TabbedDownloadManager(QTabWidget):
username=download_item.username, username=download_item.username,
soulseek_client=download_item.soulseek_client soulseek_client=download_item.soulseek_client
) )
print(f"[DEBUG] Finished queue now has {len(self.finished_queue.download_items)} items")
# Signal API that download is complete (only for completed downloads) # Signal API that download is complete (only for completed downloads)
# Note: Cancelled downloads already have their API signal sent by cancel_download() # Note: Cancelled downloads already have their API signal sent by cancel_download()
try: try:
if (download_item.status == 'completed' and if (download_item.status == 'completed' and
download_item.download_id and download_item.username and download_item.soulseek_client): download_item.download_id and download_item.username and download_item.soulseek_client):
import asyncio
# Run the async API call to signal completion # PERFORMANCE FIX: Run API cleanup in background thread to prevent UI blocking
loop = asyncio.new_event_loop() def cleanup_completed_download():
asyncio.set_event_loop(loop) try:
success = loop.run_until_complete( import asyncio
download_item.soulseek_client.signal_download_completion( loop = asyncio.new_event_loop()
download_item.download_id, asyncio.set_event_loop(loop)
download_item.username, success = loop.run_until_complete(
remove=True # Remove completed downloads from transfer list download_item.soulseek_client.signal_download_completion(
) download_item.download_id,
) download_item.username,
loop.close() remove=True
)
)
loop.close()
if success:
print(f"✓ Successfully signaled completion for download {download_item.download_id}")
else:
print(f"⚠️ Failed to signal completion for download {download_item.download_id}")
except Exception as e:
print(f"⚠️ Error signaling download completion: {e}")
# Run in background thread to prevent UI blocking
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(cleanup_completed_download)
if success:
print(f"✓ Successfully signaled completion for download {download_item.download_id}")
else:
print(f"⚠️ Failed to signal completion for download {download_item.download_id}")
except Exception as e: except Exception as e:
print(f"⚠️ Error signaling download completion: {e}") print(f"⚠️ Error setting up download completion cleanup: {e}")
self.update_tab_counts() self.update_tab_counts()
return finished_item return finished_item
@ -8968,7 +8973,6 @@ class DownloadsPage(QWidget):
download_ext = os.path.splitext(download_item.file_path)[1].lower() download_ext = os.path.splitext(download_item.file_path)[1].lower()
transfer_ext = os.path.splitext(basename)[1].lower() transfer_ext = os.path.splitext(basename)[1].lower()
print(f"[DEBUG] Comparing extensions: download='{download_ext}' vs transfer='{transfer_ext}' for '{basename}'")
# Strategy 1: Direct filename match (most reliable) # Strategy 1: Direct filename match (most reliable)
if basename_lower == download_title_lower + '.mp3' or basename_lower == download_title_lower + '.flac': if basename_lower == download_title_lower + '.mp3' or basename_lower == download_title_lower + '.flac':
@ -9043,10 +9047,9 @@ class DownloadsPage(QWidget):
if matches: if matches:
matching_transfer = transfer matching_transfer = transfer
matched_transfer_ids.add(transfer_id) matched_transfer_ids.add(transfer_id)
print(f"[DEBUG] ✅ Found filename match: {match_reason}")
break break
else: else:
print(f"[DEBUG] ❌ No match: download_title='{download_title_lower}' vs filename='{basename_lower}'") pass # No match found, continue to next transfer
if not matching_transfer: if not matching_transfer:
print(f"[DEBUG] ⚠️ No matching transfer found for download_title='{download_item.title}' by artist='{download_item.artist}'") print(f"[DEBUG] ⚠️ No matching transfer found for download_title='{download_item.title}' by artist='{download_item.artist}'")
@ -9064,7 +9067,6 @@ class DownloadsPage(QWidget):
if 'Completed' in state or 'Succeeded' in state: if 'Completed' in state or 'Succeeded' in state:
progress = 100 progress = 100
print(f"[DEBUG] Found transfer for '{download_item.title}': {state} - {progress:.1f}%")
# Map slskd states to our download states (handle compound states) # Map slskd states to our download states (handle compound states)
if 'InProgress' in state: if 'InProgress' in state:
@ -9151,6 +9153,35 @@ class DownloadsPage(QWidget):
download_speed=0, # No speed for failed download_speed=0, # No speed for failed
file_path=download_item.file_path file_path=download_item.file_path
) )
# IMMEDIATE CLEANUP: Remove errored download from API immediately
if download_item.download_id and download_item.username and download_item.soulseek_client:
def cleanup_errored_download():
try:
import asyncio
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
success = loop.run_until_complete(
download_item.soulseek_client.cancel_download(
download_item.download_id,
download_item.username,
remove=True
)
)
loop.close()
if success:
print(f"✓ Immediately cleaned up errored download {download_item.download_id}")
else:
print(f"⚠️ Failed to clean up errored download {download_item.download_id}")
except Exception as e:
print(f"⚠️ Error cleaning up errored download: {e}")
# Run cleanup in background thread
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=1) as executor:
executor.submit(cleanup_errored_download)
print(f"[DEBUG] Moving failed download '{download_item.title}' to finished queue") print(f"[DEBUG] Moving failed download '{download_item.title}' to finished queue")
self.download_queue.move_to_finished(download_item) self.download_queue.move_to_finished(download_item)
continue continue
@ -9159,6 +9190,10 @@ class DownloadsPage(QWidget):
else: else:
new_status = state.lower() new_status = state.lower()
# Reset API missing counter since we found the download
if hasattr(download_item, 'api_missing_count'):
download_item.api_missing_count = 0
# Update the download item with real-time data # Update the download item with real-time data
download_item.update_status( download_item.update_status(
status=new_status, status=new_status,
@ -9189,13 +9224,34 @@ class DownloadsPage(QWidget):
# Remove from finished queue since it's no longer in slskd # Remove from finished queue since it's no longer in slskd
self.download_queue.finished_queue.remove_download_item(download_item) self.download_queue.finished_queue.remove_download_item(download_item)
continue continue
# CRITICAL FIX: Handle active downloads that disappeared from API (errored/cancelled in backend)
elif download_item in self.download_queue.active_queue.download_items:
# Add grace period to avoid false positives during API delays
if not hasattr(download_item, 'api_missing_count'):
download_item.api_missing_count = 0
download_item.api_missing_count += 1
print(f"[DEBUG] ⚠️ Active download '{download_item.title}' not found in API (count: {download_item.api_missing_count}/3)")
# Only mark as failed after 3 consecutive misses (3 seconds with 1s polling)
if download_item.api_missing_count >= 3:
print(f"[DEBUG] ⚠️ Active download '{download_item.title}' consistently missing from API - marking as failed")
# Update status to failed since it's gone from API (likely errored or cancelled)
download_item.update_status(
status='failed',
progress=download_item.progress,
download_speed=0,
file_path=download_item.file_path
)
# Move to finished queue so user can see it failed
self.download_queue.move_to_finished(download_item)
continue
# After processing all download items, check for any that weren't found in the API # After processing all download items, check for any that weren't found in the API
# This handles the case where downloads were removed from slskd externally # This handles the case where downloads were removed from slskd externally
# Update download counters after processing all transfers # Update download counters after processing all transfers
self.download_queue.update_tab_counts() self.download_queue.update_tab_counts()
print(f"[DEBUG] Updated tab counts - Active: {len(self.download_queue.active_queue.download_items)}, Finished: {len(self.download_queue.finished_queue.download_items)}")
except Exception as e: except Exception as e:
print(f"[ERROR] Error processing transfer status update: {e}") print(f"[ERROR] Error processing transfer status update: {e}")