Add Spotify integration with improved token management and user interface
- Implemented Spotify OAuth handling in spotify_client_manager.py to ensure valid access tokens for users. - Created helper functions in spotify_helper.py for refreshing tokens and retrieving user information. - Developed manage_spotify.html template for connecting and managing Spotify accounts, displaying connection status and token information. - Added logging for token management processes to enhance debugging and monitoring. - Introduced a debug client for Spotify interactions to facilitate easier testing and development.
This commit is contained in:
@@ -5,6 +5,7 @@ import random
|
||||
import time
|
||||
from flask import current_app
|
||||
from musicround.models import Song, db
|
||||
from musicround.helpers.metadata import get_song_metadata_by_isrc
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -161,11 +162,55 @@ class DeezerClient:
|
||||
if not preview_url:
|
||||
self.logger.warning(f"Track {track_info.get('title')} has no preview URL")
|
||||
return None
|
||||
|
||||
# Extract ISRC
|
||||
isrc = track_info.get('isrc')
|
||||
|
||||
# Check if this track is already in our database
|
||||
existing_song = Song.query.filter_by(deezer_id=str(track_info['id'])).first()
|
||||
# Check if this track is already in our database by Deezer ID or ISRC
|
||||
existing_song = None
|
||||
if isrc:
|
||||
existing_song = Song.query.filter_by(isrc=isrc).first()
|
||||
if not existing_song:
|
||||
existing_song = Song.query.filter_by(deezer_id=str(track_info['id'])).first()
|
||||
|
||||
if existing_song:
|
||||
self.logger.info(f"Track {track_info.get('title')} already exists in database")
|
||||
self.logger.info(f"Track {track_info.get('title')} (Deezer ID: {track_info['id']}, ISRC: {isrc}) already exists in database with ID {existing_song.id}")
|
||||
# If ISRC was missing and we found it now, update the existing record
|
||||
if isrc and not existing_song.isrc:
|
||||
existing_song.isrc = isrc
|
||||
if existing_song.deezer_id is None: # If it was matched by ISRC but didn't have deezer_id
|
||||
existing_song.deezer_id = str(track_info['id'])
|
||||
try:
|
||||
db.session.commit()
|
||||
self.logger.info(f"Updated ISRC for existing song {existing_song.id} to {isrc}")
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
self.logger.error(f"Error updating ISRC for existing song {existing_song.id}: {e}")
|
||||
|
||||
# Optionally, trigger metadata refresh if ISRC is now available or if desired
|
||||
if existing_song.isrc:
|
||||
try:
|
||||
app_context = current_app._get_current_object()
|
||||
updated_metadata = get_song_metadata_by_isrc(existing_song.isrc, app=app_context)
|
||||
if updated_metadata:
|
||||
# Update song fields from aggregated metadata
|
||||
existing_song.title = updated_metadata.get('title', existing_song.title)
|
||||
existing_song.artist = updated_metadata.get('artist_name', existing_song.artist)
|
||||
existing_song.year = updated_metadata.get('year', existing_song.year)
|
||||
existing_song.genre = updated_metadata.get('genre', existing_song.genre)
|
||||
# ... update other relevant fields ...
|
||||
if updated_metadata.get('spotify_id') and not existing_song.spotify_id:
|
||||
existing_song.spotify_id = updated_metadata.get('spotify_id')
|
||||
if updated_metadata.get('cover_url') and not existing_song.cover_url: # Prioritize existing cover if any
|
||||
existing_song.cover_url = updated_metadata.get('cover_url')
|
||||
if updated_metadata.get('preview_url') and not existing_song.preview_url: # Prioritize existing preview if any
|
||||
existing_song.preview_url = updated_metadata.get('preview_url')
|
||||
|
||||
db.session.commit()
|
||||
self.logger.info(f"Refreshed metadata for existing song {existing_song.id} using ISRC {existing_song.isrc}")
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
self.logger.error(f"Error refreshing metadata for existing song {existing_song.id}: {e}")
|
||||
return existing_song
|
||||
|
||||
# Get additional artist details if needed
|
||||
@@ -184,27 +229,53 @@ class DeezerClient:
|
||||
# Get highest quality cover image
|
||||
cover_url = album_info.get('cover_xl') or album_info.get('cover_big') or album_info.get('cover_medium', '')
|
||||
|
||||
# Get genre from Last.fm
|
||||
genre = self.get_genre_from_lastfm(artist_name, track_info.get('title', ''), lastfm_api_key)
|
||||
# Get genre from Last.fm (can be removed if metadata aggregation handles it)
|
||||
# genre = self.get_genre_from_lastfm(artist_name, track_info.get('title', ''), lastfm_api_key)
|
||||
genre = None # Will be populated by metadata aggregation if ISRC is present
|
||||
|
||||
# Create new Song object
|
||||
new_song = Song(
|
||||
deezer_id=str(track_info['id']),
|
||||
spotify_id=None, # We don't have Spotify ID for Deezer tracks
|
||||
spotify_id=None, # Will be populated by metadata aggregation if ISRC is present
|
||||
title=track_info.get('title', ''),
|
||||
artist=artist_name,
|
||||
genre=genre,
|
||||
year=release_year,
|
||||
preview_url=preview_url,
|
||||
cover_url=cover_url,
|
||||
popularity=track_info.get('rank', 0),
|
||||
popularity=track_info.get('rank', 0), # Deezer 'rank' can be used as popularity
|
||||
isrc=isrc, # Save the ISRC
|
||||
used_count=0
|
||||
)
|
||||
|
||||
try:
|
||||
db.session.add(new_song)
|
||||
db.session.commit()
|
||||
self.logger.info(f"Imported track '{new_song.title}' by {new_song.artist}")
|
||||
self.logger.info(f"Imported track '{new_song.title}' by {new_song.artist} with Deezer ID {new_song.deezer_id} and ISRC {new_song.isrc}")
|
||||
|
||||
# If ISRC is present, fetch and update with aggregated metadata
|
||||
if new_song.isrc:
|
||||
try:
|
||||
app_context = current_app._get_current_object()
|
||||
aggregated_metadata = get_song_metadata_by_isrc(new_song.isrc, app=app_context)
|
||||
if aggregated_metadata:
|
||||
new_song.title = aggregated_metadata.get('title', new_song.title)
|
||||
new_song.artist = aggregated_metadata.get('artist_name', new_song.artist)
|
||||
new_song.year = aggregated_metadata.get('year', new_song.year)
|
||||
new_song.genre = aggregated_metadata.get('genre', new_song.genre)
|
||||
new_song.spotify_id = aggregated_metadata.get('spotify_id', new_song.spotify_id)
|
||||
# Update cover and preview URLs if they are better or missing
|
||||
if aggregated_metadata.get('cover_url'):
|
||||
new_song.cover_url = aggregated_metadata.get('cover_url')
|
||||
if aggregated_metadata.get('preview_url'):
|
||||
new_song.preview_url = aggregated_metadata.get('preview_url')
|
||||
# Potentially update popularity if a more universal score is available
|
||||
# new_song.popularity = aggregated_metadata.get('popularity', new_song.popularity)
|
||||
db.session.commit()
|
||||
self.logger.info(f"Updated new song {new_song.id} with aggregated metadata using ISRC {new_song.isrc}")
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
self.logger.error(f"Error updating new song {new_song.id} with aggregated metadata: {e}")
|
||||
return new_song
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
|
||||
Reference in New Issue
Block a user