Extract separate module for searching on spotify
This commit is contained in:
185
spotify_search.py
Normal file
185
spotify_search.py
Normal file
@@ -0,0 +1,185 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user