Mthrfkr commited on
Commit
22aed40
verified
1 Parent(s): 5d8665a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -134
app.py CHANGED
@@ -2,40 +2,24 @@ import gradio as gr
2
  import requests
3
  import pandas as pd
4
  import time
 
 
5
  from tempfile import NamedTemporaryFile
 
6
  from openpyxl import Workbook
7
- import shutil
8
 
9
  # Lista de credenciales de API de Spotify
10
- client_ids =[
11
  '9dfc90506fa04938b05d7913f8b13bad',
12
  '0ef8df0b57864accb36251fb0b741935',
13
  '066bb9a3e0ac40aba89732f9a97249bf',
14
- 'cfbe3754c86048d1a82542a5ab432b9a',
15
- '37492f29c7fe478391e8fd8fe66f3f1b',
16
- 'ac3c1dd6252740e68aeb0d7dd4e6e37d',
17
- '807008cb2ce041178c1871973fc81716',
18
- '107286416613436ab5c63b56d3564f9e',
19
- '528d1d6733ba46eb8e9532e56ced61eb',
20
- 'aed6435c51484dc18b8c18aa74dd51f8',
21
- '9df51caba5d247dc921b21de35a47c44',
22
- '191227c66e0d4be692bc8ee73ea6eb3d',
23
- 'e272c0705c7c4fd68937c58adaa446ed'
24
- ]
25
  client_secrets = [
26
  '62a96c883b564f1e8c9f3af935f9f88e',
27
  '8a1bb6f0f8f14feb9be2dff4b603bb5f',
28
  '9cdae5b56ec24aed91bb3958823ff39e',
29
- 'c55801afd5c24df3b8673cc07468c7b6',
30
- 'b61fa17afff64c8693ea5147b79562be',
31
- 'ff49073ebd324e8cac2d997a8e34644c',
32
- 'b6c3fbe2304145e4b268f05eefd6ab2a',
33
- '4de4c14ed109420c9517c083b8018f8c',
34
- '3dbdcf9a12634cfca9e6aca8d3093020',
35
- '8662b33d594f4d198ea025d4aa9f0b98',
36
- '0e39502ec7e74fe99bb74245678d5f0d',
37
- '2d2a895d85874c088897dd9894dc64ad',
38
- '9fdfa58ea0a94ce7a0cb34fa19fb7d74'
39
  ]
40
  current_api_index = 0
41
 
@@ -44,7 +28,6 @@ solicitudes_totales = 0
44
 
45
  # Funciones para Spotify
46
  def obtener_token(client_id, client_secret):
47
- print(f"Obteniendo token de Spotify con client_id: {client_id}")
48
  url = 'https://accounts.spotify.com/api/token'
49
  headers = {'Content-Type': 'application/x-www-form-urlencoded'}
50
  payload = {'grant_type': 'client_credentials'}
@@ -52,23 +35,14 @@ def obtener_token(client_id, client_secret):
52
  global solicitudes_totales
53
  solicitudes_totales += 1 # Contando solicitud
54
  if response.status_code == 200:
55
- print(f"Token obtenido exitosamente para client_id: {client_id}")
56
  return response.json().get('access_token')
57
  else:
58
- print(f"Error al obtener token para client_id: {client_id}, status_code: {response.status_code}, response: {response.text}")
59
  return None
60
 
61
- def cambiar_api_key():
62
- global current_api_index
63
- current_api_index = (current_api_index + 1) % len(client_ids)
64
- print(f"Cambiando a la siguiente API Key, 铆ndice actual: {current_api_index}")
65
- return obtener_token(client_ids[current_api_index], client_secrets[current_api_index])
66
-
67
  def manejar_rate_limit(response, intento):
68
  if response.status_code == 429:
69
  retry_after = int(response.headers.get('Retry-After', 1))
70
  wait_time = retry_after + 10 * (2 ** intento) # Retroceso exponencial
71
- print(f"L铆mite de peticiones alcanzado, Retry-After: {retry_after} segundos. Esperando {wait_time} segundos.")
72
  time.sleep(wait_time)
73
  return True
74
  return False
@@ -83,81 +57,14 @@ def hacer_request_con_reintento(url, headers, params=None, max_retries=5):
83
  if response.status_code == 200:
84
  return response
85
  else:
86
- print(f"Error en la solicitud: {response.status_code}, response: {response.text}")
87
  break
88
  return None
89
 
90
- def buscar_playlists_spotify(token, query, limit=50):
91
- print("Buscando playlists en Spotify...")
92
- url = 'https://api.spotify.com/v1/search'
93
- headers = {'Authorization': f'Bearer {token}'}
94
- playlists = []
95
-
96
- if limit <= 50:
97
- params = {'q': query, 'type': 'playlist', 'limit': limit}
98
- response = hacer_request_con_reintento(url, headers, params)
99
- if response:
100
- playlists.extend(response.json().get('playlists', {}).get('items', []))
101
- else:
102
- offset = 0
103
- while limit > 0:
104
- params = {'q': query, 'type': 'playlist', 'limit': min(50, limit), 'offset': offset}
105
- response = hacer_request_con_reintento(url, headers, params)
106
- if response:
107
- playlists.extend(response.json().get('playlists', {}).get('items', []))
108
- limit -= min(50, limit)
109
- offset += 50
110
- time.sleep(1) # Pausa de 1 segundo entre las solicitudes para evitar el l铆mite de tasa
111
- else:
112
- break
113
-
114
- return [{'playlist_id': playlist['id'], 'playlist_name': playlist['name']} for playlist in playlists]
115
-
116
- def obtener_canciones_playlist_spotify(token, playlist_id, playlist_name):
117
- print(f"Obteniendo canciones de la playlist {playlist_id} ({playlist_name}) de Spotify...")
118
- url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks'
119
- headers = {'Authorization': f'Bearer {token}'}
120
- canciones = []
121
-
122
- response = hacer_request_con_reintento(url, headers)
123
- if response:
124
- tracks = response.json().get('items')
125
- track_ids = [item['track']['id'] for item in tracks if item['track'] and item['track']['id']]
126
- album_ids = [item['track']['album']['id'] for item in tracks if item['track'] and item['track']['album']['id']]
127
-
128
- # Obtener caracter铆sticas de audio en batch
129
- audio_features = obtener_caracteristicas_audio_batch(token, track_ids)
130
- # Obtener informaci贸n de 谩lbum en batch
131
- album_info = obtener_record_label_spotify_batch(token, album_ids)
132
-
133
- for item in tracks:
134
- track = item['track']
135
- if track:
136
- audio = audio_features.get(track['id'], {})
137
- album = album_info.get(track['album']['id'], {})
138
- canciones.append({
139
- 'playlist_name': playlist_name,
140
- 'artista': track['artists'][0]['name'] if track['artists'] else 'Desconocido',
141
- 'titulo': track['name'],
142
- 'isrc': track['external_ids'].get('isrc', 'No disponible'),
143
- 'popularity': track.get('popularity', 'No disponible'),
144
- 'valence': audio.get('valence', 'No disponible'),
145
- 'danceability': audio.get('danceability', 'No disponible'),
146
- 'energy': audio.get('energy', 'No disponible'),
147
- 'tempo': audio.get('tempo', 'No disponible'),
148
- 'speechiness': audio.get('speechiness', 'No disponible'),
149
- 'instrumentalness': audio.get('instrumentalness', 'No disponible'),
150
- 'duration': track.get('duration_ms', 'No disponible'),
151
- 'release_year': track.get('album', {}).get('release_date', 'No disponible').split('-')[0] if track.get('album', {}).get('release_date') else 'No disponible',
152
- 'record_label': album.get('label', 'No disponible')
153
- })
154
- return canciones
155
-
156
- def obtener_caracteristicas_audio_batch(token, track_ids):
157
  audio_features = {}
158
  url = 'https://api.spotify.com/v1/audio-features'
159
  headers = {'Authorization': f'Bearer {token}'}
160
-
161
  for i in range(0, len(track_ids), 100):
162
  batch_ids = track_ids[i:i+100]
163
  params = {'ids': ','.join(batch_ids)}
@@ -168,44 +75,77 @@ def obtener_caracteristicas_audio_batch(token, track_ids):
168
  audio_features[feature['id']] = feature
169
  return audio_features
170
 
171
- def obtener_record_label_spotify_batch(token, album_ids):
172
- album_info = {}
173
- url = 'https://api.spotify.com/v1/albums'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  headers = {'Authorization': f'Bearer {token}'}
175
 
176
- for i in range(0, len(album_ids), 20):
177
- batch_ids = album_ids[i:i+20]
178
  params = {'ids': ','.join(batch_ids)}
179
  response = hacer_request_con_reintento(url, headers, params)
180
  if response:
181
- for album in response.json().get('albums', []):
182
- if album:
183
- album_info[album['id']] = {
184
- 'label': album.get('label', 'No disponible'),
185
- 'release_date': album.get('release_date', 'No disponible'),
186
- 'total_tracks': album.get('total_tracks', 'No disponible'),
187
- 'name': album.get('name', 'No disponible'),
188
- 'artists': [artist['name'] for artist in album.get('artists', [])]
189
- }
190
- return album_info
 
 
191
 
192
  # Funci贸n principal de la interfaz
193
- def interface(project_name, query, num_spotify_playlists=50):
194
- # Obtener tokens y claves
195
  token_spotify = obtener_token(client_ids[current_api_index], client_secrets[current_api_index])
196
- playlists_spotify = buscar_playlists_spotify(token_spotify, query, num_spotify_playlists)
197
- canciones_spotify = []
198
- for playlist in playlists_spotify:
199
- songs = obtener_canciones_playlist_spotify(token_spotify, playlist['playlist_id'], playlist['playlist_name'])
200
- canciones_spotify.extend(songs)
201
- time.sleep(1) # Pausa de 1 segundo entre la obtenci贸n de canciones para evitar el l铆mite de tasa
202
 
 
 
203
  # Crear DataFrame
204
- df = pd.DataFrame(canciones_spotify)
205
- df.rename(columns={'isrc': 'ISRCs'}, inplace=True)
206
-
207
- # Ordenar por popularidad
208
- df.sort_values(by=['popularity'], ascending=False, inplace=True)
209
 
210
  # Guardar DataFrame en un archivo Excel
211
  tmpfile = NamedTemporaryFile(delete=False, suffix='.xlsx')
@@ -222,11 +162,11 @@ iface = gr.Interface(
222
  fn=interface,
223
  inputs=[
224
  gr.Textbox(label="Nombre del Proyecto"),
225
- gr.Textbox(label="Keywords - Palabras Clave para tu b煤squeda"),
226
- gr.Number(label="Numero de Playlists que vamos a buscar con estas Keywords", value=50, minimum=1, maximum=1000)
227
  ],
228
  outputs=[gr.Dataframe(), gr.File(label="Download Excel")],
229
- title="Spotify Playlist Fetcher",
230
- description="Enter a search query to fetch playlists and their songs from Spotify. Client credentials are pre-configured."
231
  )
232
  iface.launch()
 
2
  import requests
3
  import pandas as pd
4
  import time
5
+ import shutil
6
+ import numpy as np
7
  from tempfile import NamedTemporaryFile
8
+ from sklearn.neighbors import NearestNeighbors
9
  from openpyxl import Workbook
 
10
 
11
  # Lista de credenciales de API de Spotify
12
+ client_ids = [
13
  '9dfc90506fa04938b05d7913f8b13bad',
14
  '0ef8df0b57864accb36251fb0b741935',
15
  '066bb9a3e0ac40aba89732f9a97249bf',
16
+ 'cfbe3754c86048d1a82542a5ab432b9a'
17
+ ]
 
 
 
 
 
 
 
 
 
18
  client_secrets = [
19
  '62a96c883b564f1e8c9f3af935f9f88e',
20
  '8a1bb6f0f8f14feb9be2dff4b603bb5f',
21
  '9cdae5b56ec24aed91bb3958823ff39e',
22
+ 'c55801afd5c24df3b8673cc07468c7b6'
 
 
 
 
 
 
 
 
 
23
  ]
24
  current_api_index = 0
25
 
 
28
 
29
  # Funciones para Spotify
30
  def obtener_token(client_id, client_secret):
 
31
  url = 'https://accounts.spotify.com/api/token'
32
  headers = {'Content-Type': 'application/x-www-form-urlencoded'}
33
  payload = {'grant_type': 'client_credentials'}
 
35
  global solicitudes_totales
36
  solicitudes_totales += 1 # Contando solicitud
37
  if response.status_code == 200:
 
38
  return response.json().get('access_token')
39
  else:
 
40
  return None
41
 
 
 
 
 
 
 
42
  def manejar_rate_limit(response, intento):
43
  if response.status_code == 429:
44
  retry_after = int(response.headers.get('Retry-After', 1))
45
  wait_time = retry_after + 10 * (2 ** intento) # Retroceso exponencial
 
46
  time.sleep(wait_time)
47
  return True
48
  return False
 
57
  if response.status_code == 200:
58
  return response
59
  else:
 
60
  break
61
  return None
62
 
63
+ def obtener_caracteristicas_audio(token, track_ids):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  audio_features = {}
65
  url = 'https://api.spotify.com/v1/audio-features'
66
  headers = {'Authorization': f'Bearer {token}'}
67
+
68
  for i in range(0, len(track_ids), 100):
69
  batch_ids = track_ids[i:i+100]
70
  params = {'ids': ','.join(batch_ids)}
 
75
  audio_features[feature['id']] = feature
76
  return audio_features
77
 
78
+ def obtener_tracks_y_caracteristicas(token, url):
79
+ headers = {'Authorization': f'Bearer {token}'}
80
+ if "track" in url:
81
+ track_id = url.split("/")[-1].split("?")[0]
82
+ track_ids = [track_id]
83
+ elif "playlist" in url:
84
+ playlist_id = url.split("/")[-1].split("?")[0]
85
+ tracks_url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks'
86
+ response = hacer_request_con_reintento(tracks_url, headers)
87
+ if response:
88
+ track_ids = [item['track']['id'] for item in response.json().get('items', []) if item['track']]
89
+ else:
90
+ return None, None
91
+
92
+ audio_features = obtener_caracteristicas_audio(token, track_ids)
93
+ return track_ids, audio_features
94
+
95
+ def buscar_canciones_similares(token, audio_features, n_songs=10):
96
+ features_matrix = np.array([
97
+ [v['danceability'], v['energy'], v['tempo'], v['valence']] for v in audio_features.values()
98
+ ])
99
+ neighbors = NearestNeighbors(n_neighbors=n_songs, algorithm='ball_tree').fit(features_matrix)
100
+ distances, indices = neighbors.kneighbors(features_matrix)
101
+
102
+ similar_tracks = []
103
+ for idx_list in indices:
104
+ for idx in idx_list:
105
+ similar_tracks.append(list(audio_features.keys())[idx])
106
+
107
+ # Eliminar duplicados
108
+ similar_tracks = list(set(similar_tracks))
109
+
110
+ # Limitar a las n_songs canciones m谩s similares
111
+ similar_tracks = similar_tracks[:n_songs]
112
+
113
+ return obtener_informacion_canciones(token, similar_tracks)
114
+
115
+ def obtener_informacion_canciones(token, track_ids):
116
+ tracks_info = []
117
+ url = 'https://api.spotify.com/v1/tracks'
118
  headers = {'Authorization': f'Bearer {token}'}
119
 
120
+ for i in range(0, len(track_ids), 50):
121
+ batch_ids = track_ids[i:i+50]
122
  params = {'ids': ','.join(batch_ids)}
123
  response = hacer_request_con_reintento(url, headers, params)
124
  if response:
125
+ tracks = response.json().get('tracks', [])
126
+ for track in tracks:
127
+ tracks_info.append({
128
+ 'artista': track['artists'][0]['name'] if track['artists'] else 'Desconocido',
129
+ 'titulo': track['name'],
130
+ 'isrc': track['external_ids'].get('isrc', 'No disponible'),
131
+ 'popularity': track.get('popularity', 'No disponible'),
132
+ 'release_year': track.get('album', {}).get('release_date', 'No disponible').split('-')[0] if track.get('album', {}).get('release_date') else 'No disponible',
133
+ 'duration': track.get('duration_ms', 'No disponible'),
134
+ 'url': track['external_urls']['spotify']
135
+ })
136
+ return tracks_info
137
 
138
  # Funci贸n principal de la interfaz
139
+ def interface(project_name, spotify_url, num_similar_songs=10):
 
140
  token_spotify = obtener_token(client_ids[current_api_index], client_secrets[current_api_index])
141
+ track_ids, audio_features = obtener_tracks_y_caracteristicas(token_spotify, spotify_url)
142
+ if not track_ids or not audio_features:
143
+ return "URL no v谩lida o no se encontraron canciones.", None
 
 
 
144
 
145
+ similar_tracks_info = buscar_canciones_similares(token_spotify, audio_features, num_similar_songs)
146
+
147
  # Crear DataFrame
148
+ df = pd.DataFrame(similar_tracks_info)
 
 
 
 
149
 
150
  # Guardar DataFrame en un archivo Excel
151
  tmpfile = NamedTemporaryFile(delete=False, suffix='.xlsx')
 
162
  fn=interface,
163
  inputs=[
164
  gr.Textbox(label="Nombre del Proyecto"),
165
+ gr.Textbox(label="Spotify URL (Track o Playlist)"),
166
+ gr.Number(label="N煤mero de Canciones Similares", value=10, minimum=1, maximum=100)
167
  ],
168
  outputs=[gr.Dataframe(), gr.File(label="Download Excel")],
169
+ title="Spotify Similar Track Finder",
170
+ description="Ingresa una URL de Spotify para encontrar canciones similares basadas en sus caracter铆sticas."
171
  )
172
  iface.launch()