186 lines
6.0 KiB
Python
186 lines
6.0 KiB
Python
import logging
|
|
import time
|
|
import spotipy
|
|
from spotipy.oauth2 import SpotifyClientCredentials
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="{asctime} - {levelname} - [{funcName}:{lineno}] - {message}",
|
|
style="{",
|
|
datefmt="%Y-%m-%d %H:%M",
|
|
)
|
|
|
|
def init_spotify_client():
|
|
"""
|
|
Initialize and return a Spotify client.
|
|
Requires SPOTIPY_CLIENT_ID and SPOTIPY_CLIENT_SECRET environment variables.
|
|
"""
|
|
return spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials())
|
|
|
|
|
|
def search_track(spotify, artist, title):
|
|
"""
|
|
Search for a track on Spotify.
|
|
|
|
Args:
|
|
spotify: Spotify client instance
|
|
artist: Artist name (string)
|
|
title: Track title (string)
|
|
|
|
Returns:
|
|
dict with track data if found, None otherwise. Structure:
|
|
{
|
|
'found': True,
|
|
'artist': str,
|
|
'album': str,
|
|
'album_id': str,
|
|
'release_date': str,
|
|
'release_date_precision': str,
|
|
'total_tracks': int,
|
|
'track_number': int,
|
|
'popularity': int,
|
|
'image_url': str,
|
|
'genres': list,
|
|
'label': str,
|
|
'versions_count': int
|
|
}
|
|
"""
|
|
try:
|
|
querystring = "artist:{0} track:{1}".format(artist.split("\00")[0], title)
|
|
logging.info("Searching Spotify for track with query: " + querystring)
|
|
|
|
results = spotify.search(q=querystring, type='track')
|
|
|
|
if len(results['tracks']['items']) > 0:
|
|
logging.info("Track found on Spotify!")
|
|
track = results['tracks']['items'][0]
|
|
album = track["album"]
|
|
|
|
# Get artist genres
|
|
artist_search = spotify.artist(track['artists'][0]['external_urls']['spotify'])
|
|
genres = artist_search.get('genres', [])
|
|
|
|
# Build response
|
|
data = {
|
|
'found': True,
|
|
'artist': album["artists"][0]["name"],
|
|
'album': album["name"],
|
|
'album_id': album["id"],
|
|
'release_date': album["release_date"],
|
|
'release_date_precision': album.get("release_date_precision", "day"),
|
|
'total_tracks': album["total_tracks"],
|
|
'track_number': track["track_number"],
|
|
'popularity': track["popularity"],
|
|
'image_url': album["images"][0]["url"] if album["images"] else None,
|
|
'genres': genres,
|
|
'label': album.get("label", ""),
|
|
'versions_count': len(results["tracks"]["items"])
|
|
}
|
|
|
|
logging.info(f"Found: {data['artist']} - {data['album']}")
|
|
return data
|
|
else:
|
|
logging.info("No track found on Spotify")
|
|
return None
|
|
|
|
except Exception as err:
|
|
logging.error(f"Error searching for track on Spotify: {err}")
|
|
return None
|
|
|
|
|
|
def search_album(spotify, artist, album_name):
|
|
"""
|
|
Search for an album on Spotify.
|
|
|
|
Args:
|
|
spotify: Spotify client instance
|
|
artist: Artist name (string)
|
|
album_name: Album name (string)
|
|
|
|
Returns:
|
|
dict with album data if found, None otherwise. Structure:
|
|
{
|
|
'found': True,
|
|
'artist': str,
|
|
'album': str,
|
|
'album_id': str,
|
|
'release_date': str,
|
|
'release_date_precision': str,
|
|
'total_tracks': int,
|
|
'image_url': str,
|
|
'genres': list,
|
|
'versions_count': int
|
|
}
|
|
"""
|
|
try:
|
|
querystring = "artist:{0} album:{1}".format(artist, album_name)
|
|
logging.info("Searching Spotify for album with query: " + querystring)
|
|
|
|
tries = 0
|
|
found = False
|
|
results = None
|
|
|
|
while tries < 5 and not found:
|
|
try:
|
|
results = spotify.search(q=querystring, type='album')
|
|
found = True
|
|
except Exception as err:
|
|
logging.error(f"Could not search on Spotify: {err}")
|
|
logging.info("Waiting 30 seconds before trying again")
|
|
time.sleep(30)
|
|
tries += 1
|
|
|
|
if not found or not results:
|
|
logging.error("Could not search on Spotify after 5 tries")
|
|
return None
|
|
|
|
if len(results["albums"]["items"]) > 0:
|
|
logging.info("Album found on Spotify!")
|
|
album = results["albums"]["items"][0]
|
|
|
|
# Get artist genres
|
|
artist_search = spotify.artist(album['artists'][0]['external_urls']['spotify'])
|
|
genres = artist_search.get('genres', [])
|
|
|
|
# Build response
|
|
data = {
|
|
'found': True,
|
|
'artist': album["artists"][0]["name"],
|
|
'album': album["name"],
|
|
'album_id': album["id"],
|
|
'release_date': album["release_date"],
|
|
'release_date_precision': album.get("release_date_precision", "day"),
|
|
'total_tracks': album["total_tracks"],
|
|
'image_url': album["images"][0]["url"] if album["images"] else None,
|
|
'genres': genres,
|
|
'versions_count': len(results["albums"]["items"])
|
|
}
|
|
|
|
logging.info(f"Found: {data['artist']} - {data['album']}")
|
|
return data
|
|
else:
|
|
logging.info("No album found on Spotify")
|
|
return None
|
|
|
|
except Exception as err:
|
|
logging.error(f"Error searching for album on Spotify: {err}")
|
|
return None
|
|
|
|
|
|
def format_genres(genres):
|
|
"""
|
|
Format a list of genres into a comma-separated string.
|
|
|
|
Args:
|
|
genres: list of genre strings
|
|
|
|
Returns:
|
|
Comma-separated string of genres, or empty string if no genres
|
|
"""
|
|
if not genres or len(genres) == 0:
|
|
return ""
|
|
elif len(genres) == 1:
|
|
return str(genres[0])
|
|
else:
|
|
return ",".join(genres)
|