Add post-scan phase progress to watchlist automation card
This commit is contained in:
parent
5b507d897e
commit
cdcaa245d1
2 changed files with 63 additions and 2 deletions
|
|
@ -1508,7 +1508,7 @@ class WatchlistScanner:
|
||||||
logger.error(f"Error fetching similar artists for {watchlist_artist.artist_name}: {e}")
|
logger.error(f"Error fetching similar artists for {watchlist_artist.artist_name}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def populate_discovery_pool(self, top_artists_limit: int = 50, albums_per_artist: int = 10, profile_id: int = 1):
|
def populate_discovery_pool(self, top_artists_limit: int = 50, albums_per_artist: int = 10, profile_id: int = 1, progress_callback=None):
|
||||||
"""
|
"""
|
||||||
Populate discovery pool with tracks from top similar artists.
|
Populate discovery pool with tracks from top similar artists.
|
||||||
Called after watchlist scan completes.
|
Called after watchlist scan completes.
|
||||||
|
|
@ -1529,8 +1529,14 @@ class WatchlistScanner:
|
||||||
if skip_pool_population:
|
if skip_pool_population:
|
||||||
logger.info("Discovery pool was populated recently (< 24 hours ago). Skipping pool population.")
|
logger.info("Discovery pool was populated recently (< 24 hours ago). Skipping pool population.")
|
||||||
logger.info("But still refreshing recent albums cache and curated playlists...")
|
logger.info("But still refreshing recent albums cache and curated playlists...")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('skip', 'Discovery pool recently updated, skipping')
|
||||||
# Still run these even when skipping main pool population
|
# Still run these even when skipping main pool population
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Caching recent albums...')
|
||||||
self.cache_discovery_recent_albums(profile_id=profile_id)
|
self.cache_discovery_recent_albums(profile_id=profile_id)
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Curating playlists...')
|
||||||
self.curate_discovery_playlists(profile_id=profile_id)
|
self.curate_discovery_playlists(profile_id=profile_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -1556,8 +1562,14 @@ class WatchlistScanner:
|
||||||
if not similar_artists:
|
if not similar_artists:
|
||||||
logger.info("No similar artists found to populate discovery pool from similar artists")
|
logger.info("No similar artists found to populate discovery pool from similar artists")
|
||||||
logger.info("But still caching recent albums from watchlist artists and curating playlists...")
|
logger.info("But still caching recent albums from watchlist artists and curating playlists...")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('skip', 'No similar artists found')
|
||||||
# Still run these even without similar artists - they use watchlist artists
|
# Still run these even without similar artists - they use watchlist artists
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Caching recent albums...')
|
||||||
self.cache_discovery_recent_albums(profile_id=profile_id)
|
self.cache_discovery_recent_albums(profile_id=profile_id)
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Curating playlists...')
|
||||||
self.curate_discovery_playlists(profile_id=profile_id)
|
self.curate_discovery_playlists(profile_id=profile_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -1568,6 +1580,8 @@ class WatchlistScanner:
|
||||||
for artist_idx, similar_artist in enumerate(similar_artists, 1):
|
for artist_idx, similar_artist in enumerate(similar_artists, 1):
|
||||||
try:
|
try:
|
||||||
logger.info(f"[{artist_idx}/{len(similar_artists)}] Processing {similar_artist.similar_artist_name} (occurrence: {similar_artist.occurrence_count})")
|
logger.info(f"[{artist_idx}/{len(similar_artists)}] Processing {similar_artist.similar_artist_name} (occurrence: {similar_artist.occurrence_count})")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('artist', f'{similar_artist.similar_artist_name} ({artist_idx}/{len(similar_artists)})')
|
||||||
|
|
||||||
# Build list of sources to process for this artist
|
# Build list of sources to process for this artist
|
||||||
# iTunes is ALWAYS processed (baseline), Spotify is added if authenticated
|
# iTunes is ALWAYS processed (baseline), Spotify is added if authenticated
|
||||||
|
|
@ -1766,6 +1780,8 @@ class WatchlistScanner:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
logger.info(f"Discovery pool from similar artists complete: {total_tracks_added} tracks added")
|
logger.info(f"Discovery pool from similar artists complete: {total_tracks_added} tracks added")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('success', f'Discovery pool: {total_tracks_added} tracks from {len(similar_artists)} artists')
|
||||||
|
|
||||||
# Note: Watchlist artist albums are already in discovery pool from the watchlist scan itself
|
# Note: Watchlist artist albums are already in discovery pool from the watchlist scan itself
|
||||||
# No need to re-fetch them here to avoid duplicate API calls
|
# No need to re-fetch them here to avoid duplicate API calls
|
||||||
|
|
@ -1927,10 +1943,14 @@ class WatchlistScanner:
|
||||||
|
|
||||||
# Cache recent albums for discovery page
|
# Cache recent albums for discovery page
|
||||||
logger.info("Caching recent albums for discovery page...")
|
logger.info("Caching recent albums for discovery page...")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Caching recent albums...')
|
||||||
self.cache_discovery_recent_albums(profile_id=profile_id)
|
self.cache_discovery_recent_albums(profile_id=profile_id)
|
||||||
|
|
||||||
# Curate playlists for consistent daily experience
|
# Curate playlists for consistent daily experience
|
||||||
logger.info("Curating discovery playlists...")
|
logger.info("Curating discovery playlists...")
|
||||||
|
if progress_callback:
|
||||||
|
progress_callback('phase', 'Curating playlists...')
|
||||||
self.curate_discovery_playlists(profile_id=profile_id)
|
self.curate_discovery_playlists(profile_id=profile_id)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -24850,35 +24850,66 @@ def _process_watchlist_scan_automatically(automation_id=None):
|
||||||
# Populate discovery pool from similar artists (per-profile)
|
# Populate discovery pool from similar artists (per-profile)
|
||||||
print("🎵 Starting discovery pool population...")
|
print("🎵 Starting discovery pool population...")
|
||||||
watchlist_scan_state['current_phase'] = 'populating_discovery_pool'
|
watchlist_scan_state['current_phase'] = 'populating_discovery_pool'
|
||||||
|
_update_automation_progress(automation_id, progress=96, phase='Populating discovery pool',
|
||||||
|
log_line='Building discovery pool from similar artists...', log_type='info')
|
||||||
try:
|
try:
|
||||||
|
def _discovery_progress(event_type, message):
|
||||||
|
if event_type == 'artist':
|
||||||
|
_update_automation_progress(automation_id, phase=f'Discovery pool: {message}',
|
||||||
|
log_line=message, log_type='info',
|
||||||
|
current_item=message)
|
||||||
|
elif event_type == 'phase':
|
||||||
|
_update_automation_progress(automation_id, phase=message,
|
||||||
|
log_line=message, log_type='info')
|
||||||
|
elif event_type == 'success':
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=message, log_type='success')
|
||||||
|
elif event_type == 'skip':
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=message, log_type='info')
|
||||||
|
|
||||||
for p in all_profiles:
|
for p in all_profiles:
|
||||||
scanner.populate_discovery_pool(profile_id=p['id'])
|
scanner.populate_discovery_pool(profile_id=p['id'], progress_callback=_discovery_progress)
|
||||||
print("✅ Discovery pool population complete")
|
print("✅ Discovery pool population complete")
|
||||||
except Exception as discovery_error:
|
except Exception as discovery_error:
|
||||||
print(f"⚠️ Error populating discovery pool: {discovery_error}")
|
print(f"⚠️ Error populating discovery pool: {discovery_error}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'Discovery pool error: {discovery_error}', log_type='error')
|
||||||
|
|
||||||
# Update ListenBrainz playlists cache
|
# Update ListenBrainz playlists cache
|
||||||
print("🧠 Starting ListenBrainz playlists update...")
|
print("🧠 Starting ListenBrainz playlists update...")
|
||||||
watchlist_scan_state['current_phase'] = 'updating_listenbrainz'
|
watchlist_scan_state['current_phase'] = 'updating_listenbrainz'
|
||||||
|
_update_automation_progress(automation_id, progress=97, phase='Updating ListenBrainz',
|
||||||
|
log_line='Fetching ListenBrainz playlists...', log_type='info')
|
||||||
try:
|
try:
|
||||||
from core.listenbrainz_manager import ListenBrainzManager
|
from core.listenbrainz_manager import ListenBrainzManager
|
||||||
lb_manager = ListenBrainzManager(str(get_database().database_path))
|
lb_manager = ListenBrainzManager(str(get_database().database_path))
|
||||||
lb_result = lb_manager.update_all_playlists()
|
lb_result = lb_manager.update_all_playlists()
|
||||||
if lb_result.get('success'):
|
if lb_result.get('success'):
|
||||||
summary = lb_result.get('summary', {})
|
summary = lb_result.get('summary', {})
|
||||||
|
updated = summary.get('updated', 0)
|
||||||
|
total_lb = summary.get('total', 0)
|
||||||
print(f"✅ ListenBrainz update complete: {summary}")
|
print(f"✅ ListenBrainz update complete: {summary}")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'ListenBrainz: {updated}/{total_lb} playlists updated', log_type='success')
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ ListenBrainz update had issues: {lb_result.get('error', 'Unknown error')}")
|
print(f"⚠️ ListenBrainz update had issues: {lb_result.get('error', 'Unknown error')}")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'ListenBrainz: {lb_result.get("error", "Unknown error")}', log_type='error')
|
||||||
except Exception as lb_error:
|
except Exception as lb_error:
|
||||||
print(f"⚠️ Error updating ListenBrainz: {lb_error}")
|
print(f"⚠️ Error updating ListenBrainz: {lb_error}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'ListenBrainz error: {lb_error}', log_type='error')
|
||||||
|
|
||||||
# Update current seasonal playlist (weekly refresh)
|
# Update current seasonal playlist (weekly refresh)
|
||||||
print("🎃 Starting seasonal content update...")
|
print("🎃 Starting seasonal content update...")
|
||||||
watchlist_scan_state['current_phase'] = 'updating_seasonal'
|
watchlist_scan_state['current_phase'] = 'updating_seasonal'
|
||||||
|
_update_automation_progress(automation_id, progress=98, phase='Updating seasonal content',
|
||||||
|
log_line='Checking seasonal playlists...', log_type='info')
|
||||||
try:
|
try:
|
||||||
from core.seasonal_discovery import get_seasonal_discovery_service
|
from core.seasonal_discovery import get_seasonal_discovery_service
|
||||||
seasonal_service = get_seasonal_discovery_service(spotify_client, database)
|
seasonal_service = get_seasonal_discovery_service(spotify_client, database)
|
||||||
|
|
@ -24888,17 +24919,27 @@ def _process_watchlist_scan_automatically(automation_id=None):
|
||||||
if current_season:
|
if current_season:
|
||||||
if seasonal_service.should_populate_seasonal_content(current_season, days_threshold=7):
|
if seasonal_service.should_populate_seasonal_content(current_season, days_threshold=7):
|
||||||
print(f"🎃 Updating {current_season} seasonal content...")
|
print(f"🎃 Updating {current_season} seasonal content...")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'Updating {current_season} seasonal content...', log_type='info')
|
||||||
seasonal_service.populate_seasonal_content(current_season)
|
seasonal_service.populate_seasonal_content(current_season)
|
||||||
seasonal_service.curate_seasonal_playlist(current_season)
|
seasonal_service.curate_seasonal_playlist(current_season)
|
||||||
print(f"✅ {current_season.capitalize()} seasonal content updated")
|
print(f"✅ {current_season.capitalize()} seasonal content updated")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'{current_season.capitalize()} seasonal content updated', log_type='success')
|
||||||
else:
|
else:
|
||||||
print(f"⏭️ {current_season.capitalize()} seasonal content recently updated, skipping")
|
print(f"⏭️ {current_season.capitalize()} seasonal content recently updated, skipping")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'{current_season.capitalize()} seasonal content up to date', log_type='info')
|
||||||
else:
|
else:
|
||||||
print("ℹ️ No active season at this time")
|
print("ℹ️ No active season at this time")
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line='No active season', log_type='info')
|
||||||
except Exception as seasonal_error:
|
except Exception as seasonal_error:
|
||||||
print(f"⚠️ Error updating seasonal content: {seasonal_error}")
|
print(f"⚠️ Error updating seasonal content: {seasonal_error}")
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
_update_automation_progress(automation_id,
|
||||||
|
log_line=f'Seasonal error: {seasonal_error}', log_type='error')
|
||||||
|
|
||||||
# Add activity for watchlist scan completion
|
# Add activity for watchlist scan completion
|
||||||
if total_added_to_wishlist > 0:
|
if total_added_to_wishlist > 0:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue