cleanup
This commit is contained in:
parent
054665e494
commit
b5ed2b0e5f
6 changed files with 18429 additions and 1 deletions
Binary file not shown.
|
|
@ -542,7 +542,7 @@ class SoulseekClient:
|
|||
|
||||
return None
|
||||
|
||||
async def search(self, query: str, timeout: int = 35, progress_callback=None) -> tuple[List[TrackResult], List[AlbumResult]]:
|
||||
async def search(self, query: str, timeout: int = 60, progress_callback=None) -> tuple[List[TrackResult], List[AlbumResult]]:
|
||||
if not self.base_url:
|
||||
logger.error("Soulseek client not configured")
|
||||
return [], []
|
||||
|
|
@ -937,6 +937,207 @@ class SoulseekClient:
|
|||
logger.error(f"Error clearing completed downloads: {e}")
|
||||
return False
|
||||
|
||||
async def get_all_searches(self) -> List[dict]:
|
||||
"""Get all search history from slskd
|
||||
|
||||
Returns:
|
||||
List[dict]: List of search objects from slskd API, empty list if error
|
||||
"""
|
||||
if not self.base_url:
|
||||
logger.error("Soulseek client not configured")
|
||||
return []
|
||||
|
||||
try:
|
||||
endpoint = 'searches'
|
||||
logger.debug(f"Getting all searches with endpoint: {endpoint}")
|
||||
response = await self._make_request('GET', endpoint)
|
||||
|
||||
if response is not None:
|
||||
searches = response if isinstance(response, list) else []
|
||||
logger.info(f"Retrieved {len(searches)} searches from slskd")
|
||||
return searches
|
||||
else:
|
||||
logger.error("Failed to retrieve searches from slskd")
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving searches: {e}")
|
||||
return []
|
||||
|
||||
async def delete_search(self, search_id: str) -> bool:
|
||||
"""Delete a specific search from slskd history
|
||||
|
||||
Args:
|
||||
search_id: The ID of the search to delete
|
||||
|
||||
Returns:
|
||||
bool: True if deletion was successful, False otherwise
|
||||
"""
|
||||
if not self.base_url:
|
||||
logger.error("Soulseek client not configured")
|
||||
return False
|
||||
|
||||
try:
|
||||
endpoint = f'searches/{search_id}'
|
||||
logger.debug(f"Deleting search {search_id} with endpoint: {endpoint}")
|
||||
response = await self._make_request('DELETE', endpoint)
|
||||
success = response is not None
|
||||
|
||||
if success:
|
||||
logger.debug(f"Successfully deleted search {search_id}")
|
||||
else:
|
||||
logger.warning(f"Failed to delete search {search_id}")
|
||||
|
||||
return success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting search {search_id}: {e}")
|
||||
return False
|
||||
|
||||
async def clear_all_searches(self) -> bool:
|
||||
"""Clear all search history from slskd
|
||||
|
||||
Returns:
|
||||
bool: True if all searches were cleared successfully, False otherwise
|
||||
"""
|
||||
if not self.base_url:
|
||||
logger.error("Soulseek client not configured")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get all searches first
|
||||
searches = await self.get_all_searches()
|
||||
|
||||
if not searches:
|
||||
logger.info("No searches found to clear")
|
||||
return True
|
||||
|
||||
logger.info(f"Clearing {len(searches)} searches from slskd...")
|
||||
|
||||
# Delete each search individually
|
||||
deleted_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for search in searches:
|
||||
search_id = search.get('id')
|
||||
if search_id:
|
||||
success = await self.delete_search(search_id)
|
||||
if success:
|
||||
deleted_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
else:
|
||||
logger.warning("Search found without ID, skipping")
|
||||
failed_count += 1
|
||||
|
||||
logger.info(f"Search cleanup complete: {deleted_count} deleted, {failed_count} failed")
|
||||
return failed_count == 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error clearing all searches: {e}")
|
||||
return False
|
||||
|
||||
async def maintain_search_history(self, max_searches: int = 50) -> bool:
|
||||
"""Maintain a rolling window of recent searches by deleting oldest when over limit
|
||||
|
||||
Args:
|
||||
max_searches: Maximum number of searches to keep (default: 50)
|
||||
|
||||
Returns:
|
||||
bool: True if maintenance was successful, False otherwise
|
||||
"""
|
||||
if not self.base_url:
|
||||
logger.debug("Soulseek client not configured, skipping search maintenance")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get all searches (should be ordered by creation time, oldest first)
|
||||
searches = await self.get_all_searches()
|
||||
|
||||
if len(searches) <= max_searches:
|
||||
logger.debug(f"Search count ({len(searches)}) within limit ({max_searches}), no maintenance needed")
|
||||
return True
|
||||
|
||||
# Calculate how many to delete
|
||||
excess_count = len(searches) - max_searches
|
||||
oldest_searches = searches[:excess_count] # Get the oldest ones
|
||||
|
||||
logger.info(f"Maintaining search history: deleting {excess_count} oldest searches (keeping {max_searches})")
|
||||
|
||||
# Delete the oldest searches
|
||||
deleted_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for search in oldest_searches:
|
||||
search_id = search.get('id')
|
||||
if search_id:
|
||||
success = await self.delete_search(search_id)
|
||||
if success:
|
||||
deleted_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
else:
|
||||
logger.warning("Search found without ID during maintenance, skipping")
|
||||
failed_count += 1
|
||||
|
||||
logger.info(f"Search maintenance complete: {deleted_count} deleted, {failed_count} failed")
|
||||
return failed_count == 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during search history maintenance: {e}")
|
||||
return False
|
||||
|
||||
async def maintain_search_history_with_buffer(self, keep_searches: int = 50, trigger_threshold: int = 200) -> bool:
|
||||
"""Maintain search history with a buffer - only clean when searches exceed threshold
|
||||
|
||||
Args:
|
||||
keep_searches: Number of searches to keep after cleanup (default: 50)
|
||||
trigger_threshold: Only trigger cleanup when search count exceeds this (default: 200)
|
||||
|
||||
Returns:
|
||||
bool: True if maintenance was successful or not needed, False otherwise
|
||||
"""
|
||||
if not self.base_url:
|
||||
logger.debug("Soulseek client not configured, skipping search maintenance")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Get all searches
|
||||
searches = await self.get_all_searches()
|
||||
|
||||
if len(searches) <= trigger_threshold:
|
||||
logger.debug(f"Search count ({len(searches)}) below trigger threshold ({trigger_threshold}), no maintenance needed")
|
||||
return True
|
||||
|
||||
# Calculate how many to delete (keep only the most recent ones)
|
||||
excess_count = len(searches) - keep_searches
|
||||
oldest_searches = searches[:excess_count] # Get the oldest ones to delete
|
||||
|
||||
logger.info(f"Search buffer exceeded: {len(searches)} searches > {trigger_threshold} threshold. Deleting {excess_count} oldest searches (keeping {keep_searches})")
|
||||
|
||||
# Delete the oldest searches
|
||||
deleted_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for search in oldest_searches:
|
||||
search_id = search.get('id')
|
||||
if search_id:
|
||||
success = await self.delete_search(search_id)
|
||||
if success:
|
||||
deleted_count += 1
|
||||
else:
|
||||
failed_count += 1
|
||||
else:
|
||||
logger.warning("Search found without ID during maintenance, skipping")
|
||||
failed_count += 1
|
||||
|
||||
logger.info(f"Search buffer maintenance complete: {deleted_count} deleted, {failed_count} failed, {keep_searches} searches remaining")
|
||||
return failed_count == 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during search history buffer maintenance: {e}")
|
||||
return False
|
||||
|
||||
async def search_and_download_best(self, query: str, preferred_quality: str = 'flac') -> Optional[str]:
|
||||
results = await self.search(query)
|
||||
|
||||
|
|
|
|||
18170
logs/app.log
18170
logs/app.log
File diff suppressed because it is too large
Load diff
57
main.py
57
main.py
|
|
@ -68,6 +68,58 @@ class MainWindow(QMainWindow):
|
|||
self.status_thread = None
|
||||
self.init_ui()
|
||||
self.setup_status_monitoring()
|
||||
|
||||
# Setup periodic search maintenance (rolling 50-search window)
|
||||
self.setup_search_maintenance()
|
||||
|
||||
def setup_search_maintenance(self):
|
||||
"""Setup periodic search history maintenance to keep only the 50 most recent searches"""
|
||||
try:
|
||||
# Create timer for periodic search maintenance
|
||||
self.search_maintenance_timer = QTimer()
|
||||
self.search_maintenance_timer.timeout.connect(self._run_search_maintenance)
|
||||
|
||||
# Run maintenance every 2 minutes (120 seconds)
|
||||
# This keeps search history clean without being too frequent
|
||||
self.search_maintenance_timer.start(120000)
|
||||
|
||||
logger.info("Search maintenance timer started (every 2 minutes, keeps 200 most recent searches)")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error setting up search maintenance: {e}")
|
||||
|
||||
def _run_search_maintenance(self):
|
||||
"""Run search maintenance in background thread to avoid blocking UI"""
|
||||
try:
|
||||
# Only run if Soulseek client seems to be available
|
||||
if hasattr(self.soulseek_client, 'base_url') and self.soulseek_client.base_url:
|
||||
# Run maintenance in background thread
|
||||
import threading
|
||||
|
||||
def maintenance_thread():
|
||||
try:
|
||||
import asyncio
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
# Run the maintenance (keep 200 most recent searches)
|
||||
success = loop.run_until_complete(self.soulseek_client.maintain_search_history(200))
|
||||
|
||||
if not success:
|
||||
logger.warning("Search maintenance completed with some failures")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in search maintenance thread: {e}")
|
||||
finally:
|
||||
loop.close()
|
||||
|
||||
thread = threading.Thread(target=maintenance_thread, daemon=True)
|
||||
thread.start()
|
||||
else:
|
||||
logger.debug("Soulseek client not configured, skipping search maintenance")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error running search maintenance: {e}")
|
||||
|
||||
def init_ui(self):
|
||||
self.setWindowTitle("NewMusic - Music Sync & Manager")
|
||||
|
|
@ -204,6 +256,11 @@ class MainWindow(QMainWindow):
|
|||
logger.info("Stopping status monitoring thread...")
|
||||
self.status_thread.stop()
|
||||
|
||||
# Stop search maintenance timer
|
||||
if hasattr(self, 'search_maintenance_timer') and self.search_maintenance_timer:
|
||||
logger.info("Stopping search maintenance timer...")
|
||||
self.search_maintenance_timer.stop()
|
||||
|
||||
# Close Soulseek client
|
||||
try:
|
||||
logger.info("Closing Soulseek client...")
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue