| import gradio as gr |
| import requests |
| import pandas as pd |
| from tempfile import NamedTemporaryFile |
| import shutil |
| import os |
|
|
| |
| def obtener_token(client_id, client_secret): |
| print("Obteniendo token de Spotify...") |
| url = 'https://accounts.spotify.com/api/token' |
| headers = {'Content-Type': 'application/x-www-form-urlencoded'} |
| payload = {'grant_type': 'client_credentials'} |
| response = requests.post(url, headers=headers, data=payload, auth=(client_id, client_secret)) |
| return response.json().get('access_token') |
|
|
| def buscar_playlists_spotify(token, query, limit=50): |
| print("Buscando playlists en Spotify...") |
| url = 'https://api.spotify.com/v1/search' |
| headers = {'Authorization': f'Bearer {token}'} |
| playlists = [] |
|
|
| if limit <= 50: |
| params = {'q': query, 'type': 'playlist', 'limit': limit} |
| response = requests.get(url, headers=headers, params=params) |
| if response.status_code != 200: |
| print(f"Error en la solicitud a Spotify: {response.status_code}") |
| print(response.json()) |
| return [] |
| items = response.json().get('playlists', {}).get('items', []) |
| items = [item for item in items if item is not None] |
| playlists.extend(items) |
| else: |
| offset = 0 |
| while limit > 0: |
| params = {'q': query, 'type': 'playlist', 'limit': min(50, limit), 'offset': offset} |
| response = requests.get(url, headers=headers, params=params) |
| if response.status_code != 200: |
| print(f"Error en la solicitud a Spotify: {response.status_code}") |
| print(response.json()) |
| break |
| items = response.json().get('playlists', {}).get('items', []) |
| items = [item for item in items if item is not None] |
| playlists.extend(items) |
| fetched = len(items) |
| limit -= fetched |
| offset += fetched |
| if fetched == 0: |
| break |
|
|
| valid_playlists = [] |
| for playlist in playlists: |
| if playlist is not None and 'id' in playlist and 'name' in playlist: |
| valid_playlists.append({ |
| 'playlist_id': playlist['id'], |
| 'playlist_name': playlist['name'] |
| }) |
| return valid_playlists |
|
|
| def obtener_canciones_playlist_spotify(token, playlist_id, playlist_name): |
| print(f"Obteniendo canciones de la playlist {playlist_id} de Spotify...") |
| url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks' |
| headers = {'Authorization': f'Bearer {token}'} |
| response = requests.get(url, headers=headers) |
| canciones = [] |
| if response.status_code == 200: |
| tracks = response.json().get('items', []) |
| for item in tracks: |
| track = item.get('track') |
| if track: |
| artista_info = {} |
| if track['artists']: |
| artista_info = obtener_info_artista(track['artists'][0]['id'], token) |
| record_label = obtener_record_label_spotify(track['album']['id'], token) if track.get('album') else 'No disponible' |
| canciones.append({ |
| 'playlist_name': playlist_name, |
| 'artista': track['artists'][0]['name'] if track['artists'] else 'Desconocido', |
| 'titulo': track['name'], |
| 'isrc': track.get('external_ids', {}).get('isrc', 'No disponible'), |
| 'popularity': track.get('popularity', 'No disponible'), |
| 'track_id': track['id'], |
| 'link': track.get('external_urls', {}).get('spotify', 'No disponible'), |
| 'record_label': record_label, |
| 'source': 'Spotify', |
| 'genero_artista': ', '.join(artista_info.get('genres', [])) if artista_info else 'No disponible' |
| }) |
| return canciones |
|
|
| def obtener_caracteristicas_audio(token, track_ids): |
| print("Obteniendo características de audio para las pistas...") |
| url = f'https://api.spotify.com/v1/audio-features' |
| headers = {'Authorization': f'Bearer {token}'} |
| params = {'ids': ','.join(track_ids)} |
| response = requests.get(url, headers=headers, params=params) |
| return response.json().get('audio_features', []) if response.status_code == 200 else [] |
|
|
| def obtener_record_label_spotify(album_id, token): |
| url = f'https://api.spotify.com/v1/albums/{album_id}' |
| headers = {'Authorization': f'Bearer {token}'} |
| response = requests.get(url, headers=headers) |
| return response.json().get('label', 'No disponible') if response.status_code == 200 else 'No disponible' |
|
|
| def obtener_info_artista(artista_id, token): |
| url = f'https://api.spotify.com/v1/artists/{artista_id}' |
| headers = {'Authorization': f'Bearer {token}'} |
| response = requests.get(url, headers=headers) |
| return response.json() if response.status_code == 200 else {} |
|
|
| def interface(query, num_spotify_playlists=50, project_name="Proyecto"): |
| client_id = os.getenv('Spotify_ID') |
| client_secret = os.getenv('Spotify_client') |
|
|
| token_spotify = obtener_token(client_id, client_secret) |
| if not token_spotify: |
| raise gr.Error("Failed to obtain Spotify token. Check client ID and secret.") |
|
|
| playlists_spotify = buscar_playlists_spotify(token_spotify, query, num_spotify_playlists) |
| canciones_spotify = [] |
| track_ids = [] |
| for playlist in playlists_spotify: |
| songs = obtener_canciones_playlist_spotify(token_spotify, playlist['playlist_id'], playlist['playlist_name']) |
| canciones_spotify.extend(songs) |
| track_ids.extend([song['track_id'] for song in songs if song.get('track_id')]) |
|
|
| audio_features_list = obtener_caracteristicas_audio(token_spotify, track_ids) |
| audio_features_dict = {af['id']: af for af in audio_features_list if af} |
|
|
| for song in canciones_spotify: |
| audio_features = audio_features_dict.get(song['track_id'], {}) |
| song.update({ |
| 'valence': audio_features.get('valence', 'No disponible'), |
| 'danceability': audio_features.get('danceability', 'No disponible'), |
| 'energy': audio_features.get('energy', 'No disponible'), |
| 'tempo': audio_features.get('tempo', 'No disponible'), |
| 'speechiness': audio_features.get('speechiness', 'No disponible'), |
| 'instrumentalness': audio_features.get('instrumentalness', 'No disponible') |
| }) |
|
|
| df = pd.DataFrame(canciones_spotify) |
| df.rename(columns={'isrc': 'ISRCs'}, inplace=True) |
| df.sort_values(by=['popularity'], ascending=False, inplace=True) |
|
|
| with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmpfile: |
| df.to_excel(tmpfile.name, index=False) |
| project_filename = f"{project_name}.xlsx" |
| shutil.move(tmpfile.name, project_filename) |
| return df, project_filename |
|
|
| iface = gr.Interface( |
| fn=interface, |
| inputs=[ |
| gr.Textbox(label="Keywords o Títulos de Playlists"), |
| gr.Number(label="Número de playlists que queremos buscar", value=50, minimum=1, maximum=1000), |
| gr.Textbox(label="Nombre del proyecto") |
| ], |
| outputs=[gr.Dataframe(), gr.File(label="Descargar Excel")], |
| title="Busca Playlists con Keywords", |
| description="Ingresa tu búsqueda para encontrar playlists en Spotify con esas palabras en sus títulos." |
| ) |
| iface.launch() |