add spotify liked songs playlist
This commit is contained in:
parent
781d869f74
commit
b16318f37e
2 changed files with 126 additions and 8 deletions
|
|
@ -293,6 +293,68 @@ class SpotifyClient:
|
||||||
logger.error(f"Error fetching user playlists metadata: {e}")
|
logger.error(f"Error fetching user playlists metadata: {e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@rate_limited
|
||||||
|
def get_saved_tracks_count(self) -> int:
|
||||||
|
"""Get the total count of user's saved/liked songs without fetching all tracks"""
|
||||||
|
if not self.is_authenticated():
|
||||||
|
logger.error("Not authenticated with Spotify")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Just fetch first page to get the total count
|
||||||
|
results = self.sp.current_user_saved_tracks(limit=1)
|
||||||
|
if results and 'total' in results:
|
||||||
|
total_count = results['total']
|
||||||
|
logger.info(f"User has {total_count} saved tracks")
|
||||||
|
return total_count
|
||||||
|
return 0
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error fetching saved tracks count: {e}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@rate_limited
|
||||||
|
def get_saved_tracks(self) -> List[Track]:
|
||||||
|
"""Fetch all user's saved/liked songs from Spotify"""
|
||||||
|
if not self.is_authenticated():
|
||||||
|
logger.error("Not authenticated with Spotify")
|
||||||
|
return []
|
||||||
|
|
||||||
|
tracks = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
limit = 50 # Maximum allowed by Spotify API
|
||||||
|
offset = 0
|
||||||
|
total_fetched = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
results = self.sp.current_user_saved_tracks(limit=limit, offset=offset)
|
||||||
|
|
||||||
|
if not results or 'items' not in results:
|
||||||
|
break
|
||||||
|
|
||||||
|
batch_count = 0
|
||||||
|
for item in results['items']:
|
||||||
|
if item['track'] and item['track']['id']:
|
||||||
|
track = Track.from_spotify_track(item['track'])
|
||||||
|
tracks.append(track)
|
||||||
|
batch_count += 1
|
||||||
|
|
||||||
|
total_fetched += batch_count
|
||||||
|
logger.info(f"Retrieved {batch_count} saved tracks in batch (offset {offset}), total: {total_fetched}")
|
||||||
|
|
||||||
|
# Check if we've fetched all saved tracks
|
||||||
|
if len(results['items']) < limit or not results.get('next'):
|
||||||
|
break
|
||||||
|
|
||||||
|
offset += limit
|
||||||
|
|
||||||
|
logger.info(f"Retrieved {len(tracks)} total saved tracks")
|
||||||
|
return tracks
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error fetching saved tracks: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
@rate_limited
|
@rate_limited
|
||||||
def _get_playlist_tracks(self, playlist_id: str) -> List[Track]:
|
def _get_playlist_tracks(self, playlist_id: str) -> List[Track]:
|
||||||
if not self.is_authenticated():
|
if not self.is_authenticated():
|
||||||
|
|
|
||||||
|
|
@ -11608,6 +11608,8 @@ def get_spotify_playlists():
|
||||||
sync_statuses = _load_sync_status_file()
|
sync_statuses = _load_sync_status_file()
|
||||||
|
|
||||||
playlist_data = []
|
playlist_data = []
|
||||||
|
|
||||||
|
# Add regular playlists first
|
||||||
for p in playlists:
|
for p in playlists:
|
||||||
status_info = sync_statuses.get(p.id, {})
|
status_info = sync_statuses.get(p.id, {})
|
||||||
sync_status = "Never Synced"
|
sync_status = "Never Synced"
|
||||||
|
|
@ -11640,6 +11642,38 @@ def get_spotify_playlists():
|
||||||
"sync_status": sync_status,
|
"sync_status": sync_status,
|
||||||
"snapshot_id": playlist_snapshot
|
"snapshot_id": playlist_snapshot
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Add virtual "Liked Songs" playlist at the END (just count, no full fetch)
|
||||||
|
try:
|
||||||
|
liked_songs_count = spotify_client.get_saved_tracks_count()
|
||||||
|
if liked_songs_count > 0:
|
||||||
|
liked_songs_id = "spotify:liked-songs"
|
||||||
|
status_info = sync_statuses.get(liked_songs_id, {})
|
||||||
|
sync_status = "Never Synced"
|
||||||
|
|
||||||
|
if 'last_synced' in status_info:
|
||||||
|
last_sync_time = datetime.fromisoformat(status_info['last_synced']).strftime('%b %d, %H:%M')
|
||||||
|
sync_status = f"Synced: {last_sync_time}"
|
||||||
|
|
||||||
|
# Get user info for owner name
|
||||||
|
user_info = spotify_client.get_user_info()
|
||||||
|
owner_name = user_info.get('display_name', 'You') if user_info else 'You'
|
||||||
|
|
||||||
|
# Add Liked Songs as LAST playlist
|
||||||
|
playlist_data.append({
|
||||||
|
"id": liked_songs_id,
|
||||||
|
"name": "Liked Songs",
|
||||||
|
"owner": owner_name,
|
||||||
|
"track_count": liked_songs_count,
|
||||||
|
"image_url": None, # Spotify doesn't provide image for Liked Songs
|
||||||
|
"sync_status": sync_status,
|
||||||
|
"snapshot_id": "" # Liked Songs doesn't have a snapshot_id
|
||||||
|
})
|
||||||
|
print(f"🔍 Added virtual 'Liked Songs' playlist with {liked_songs_count} tracks (count only)")
|
||||||
|
except Exception as liked_error:
|
||||||
|
print(f"⚠️ Failed to add Liked Songs playlist: {liked_error}")
|
||||||
|
# Don't fail the entire request if Liked Songs fails
|
||||||
|
|
||||||
return jsonify(playlist_data)
|
return jsonify(playlist_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"error": str(e)}), 500
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
@ -11650,6 +11684,28 @@ def get_playlist_tracks(playlist_id):
|
||||||
if not spotify_client or not spotify_client.is_authenticated():
|
if not spotify_client or not spotify_client.is_authenticated():
|
||||||
return jsonify({"error": "Spotify not authenticated."}), 401
|
return jsonify({"error": "Spotify not authenticated."}), 401
|
||||||
try:
|
try:
|
||||||
|
# Handle special "Liked Songs" virtual playlist
|
||||||
|
if playlist_id == "spotify:liked-songs":
|
||||||
|
saved_tracks = spotify_client.get_saved_tracks()
|
||||||
|
user_info = spotify_client.get_user_info()
|
||||||
|
owner_name = user_info.get('display_name', 'You') if user_info else 'You'
|
||||||
|
|
||||||
|
# Create virtual playlist dict for Liked Songs
|
||||||
|
playlist_dict = {
|
||||||
|
'id': 'spotify:liked-songs',
|
||||||
|
'name': 'Liked Songs',
|
||||||
|
'description': 'Your saved tracks on Spotify',
|
||||||
|
'owner': owner_name,
|
||||||
|
'public': False,
|
||||||
|
'collaborative': False,
|
||||||
|
'track_count': len(saved_tracks),
|
||||||
|
'image_url': None,
|
||||||
|
'snapshot_id': '',
|
||||||
|
'tracks': [{'id': t.id, 'name': t.name, 'artists': t.artists, 'album': t.album, 'duration_ms': t.duration_ms, 'popularity': t.popularity} for t in saved_tracks]
|
||||||
|
}
|
||||||
|
return jsonify(playlist_dict)
|
||||||
|
|
||||||
|
# Handle regular playlists
|
||||||
# This reuses the robust track fetching logic from your GUI's sync.py
|
# This reuses the robust track fetching logic from your GUI's sync.py
|
||||||
full_playlist = spotify_client.get_playlist_by_id(playlist_id)
|
full_playlist = spotify_client.get_playlist_by_id(playlist_id)
|
||||||
if not full_playlist:
|
if not full_playlist:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue