Mthrfkr commited on
Commit
ee5220b
·
verified ·
1 Parent(s): 1c1ec30

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +34 -34
app.py CHANGED
@@ -11,7 +11,7 @@ client_ids = os.getenv("SPOTIFY_CLIENT_IDS", "").split(',')
11
  client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')
12
 
13
  if not client_ids or not client_secrets:
14
- raise ValueError("❌ Faltan variables de entorno SPOTIFY_CLIENT_IDS o SPOTIFY_CLIENT_SECRETS")
15
 
16
  # Gestión de Rotación de Clientes
17
  current_client_index = 0
@@ -22,7 +22,7 @@ def rotate_client():
22
  global current_client_index, request_counter
23
  current_client_index = (current_client_index + 1) % len(client_ids)
24
  request_counter = 0
25
- print(f"🔄 Rotando a cliente Spotify #{current_client_index + 1}")
26
 
27
  def get_spotify_token():
28
  global current_client_index
@@ -40,10 +40,10 @@ def get_spotify_token():
40
  if response.status_code == 200:
41
  return response.json().get('access_token')
42
 
43
- print(f"❌ Error con cliente {current_client_index}: {response.text}")
44
  rotate_client()
45
 
46
- raise Exception("🚨 Todos los clientes fallaron al obtener token")
47
 
48
  def make_spotify_request(url, params=None):
49
  global request_counter
@@ -55,9 +55,9 @@ def make_spotify_request(url, params=None):
55
  request_counter += 1
56
 
57
  if response.status_code == 429:
58
- print(f"⚠️ Límite de tasa alcanzado. Cliente: {current_client_index}")
59
  rotate_client()
60
- time.sleep(int(response.headers.get('Retry-After', 10))) # Espera mínima de 10 segundos
61
  continue
62
 
63
  if response.status_code == 200:
@@ -71,10 +71,10 @@ def make_spotify_request(url, params=None):
71
  return None
72
 
73
  def extract_spotify_id(url, resource_type):
74
- """Extrae ID de diferentes formatos de URLs de Spotify"""
75
  clean_url = url.strip().split('?')[0].replace("https://open.spotify.com/", "")
76
 
77
- # Manejar URLs con /intl-xx/
78
  if "/intl-" in clean_url:
79
  parts = clean_url.split("/")
80
  return parts[-1]
@@ -93,10 +93,10 @@ def extract_spotify_id(url, resource_type):
93
  def get_playlist_tracks(playlist_url):
94
  playlist_id = extract_spotify_id(playlist_url, "playlist")
95
  if not playlist_id or len(playlist_id) != 22:
96
- print(f"❌ ID de playlist inválido: {playlist_id}")
97
  return []
98
 
99
- print(f"🎧 Obteniendo playlist: {playlist_id}")
100
  all_tracks = []
101
  url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks'
102
  params = {'market': 'US', 'limit': 100}
@@ -109,16 +109,16 @@ def get_playlist_tracks(playlist_url):
109
  all_tracks.extend([item['track'] for item in data.get('items', []) if item.get('track')])
110
  url = data.get('next')
111
 
112
- print(f"✅ Encontrados {len(all_tracks)} tracks")
113
  return all_tracks
114
 
115
  def get_album_tracks(album_url):
116
  album_id = extract_spotify_id(album_url, "album")
117
  if not album_id or len(album_id) != 22:
118
- print(f"❌ ID de álbum inválido: {album_id}")
119
  return []
120
 
121
- print(f"💿 Obteniendo álbum: {album_id}")
122
  all_tracks = []
123
  url = f'https://api.spotify.com/v1/albums/{album_id}/tracks'
124
  params = {'market': 'US', 'limit': 50}
@@ -153,7 +153,7 @@ def process_tracks(urls):
153
  if track_data:
154
  all_tracks.append(track_data)
155
  except Exception as e:
156
- print(f"⚠️ Error procesando {url}: {str(e)}")
157
 
158
  return all_tracks
159
 
@@ -181,9 +181,9 @@ def create_final_dataframe(tracks, include_all_info=True):
181
  duration_min = f"{track['duration_ms']//60000}:{str(track['duration_ms']%60000//1000).zfill(2)}"
182
 
183
  track_data = {
184
- 'Artist': main_artist.get('name', 'Desconocido'),
185
- 'Title': track.get('name', 'Sin título'),
186
- 'Album': track.get('album', {}).get('name', 'Sin álbum'),
187
  'ISRC': track.get('external_ids', {}).get('isrc', 'Not available'),
188
  'Popularity': track.get('popularity', 0),
189
  'Duration': duration_min,
@@ -205,7 +205,7 @@ def create_final_dataframe(tracks, include_all_info=True):
205
 
206
  df = pd.DataFrame(processed)
207
 
208
- # Eliminar duplicados usando ISRC o combinación artista-título
209
  df['dup_key'] = df.apply(
210
  lambda x: x['ISRC'] if x['ISRC'] != 'Not available' else f"{x['Artist']}|{x['Title']}",
211
  axis=1
@@ -215,19 +215,19 @@ def create_final_dataframe(tracks, include_all_info=True):
215
  return df
216
 
217
  def main_interface(project_name, spotify_urls, include_all_info=True):
218
- # Convertir URLs separadas por comas o saltos de línea
219
  urls = [url.strip() for url in spotify_urls.replace('\n', ',').split(',') if url.strip()]
220
 
221
  if not urls:
222
- return pd.DataFrame({"Error": ["❌ Ingresa al menos una URL válida"]}), None
223
 
224
- print("⏳ Procesando URLs...")
225
  tracks = process_tracks(urls)
226
 
227
  if not tracks:
228
- return pd.DataFrame({"Error": ["❌ No se encontraron tracks"]}), None
229
 
230
- print("📊 Creando dataframe...")
231
  df = create_final_dataframe(tracks, include_all_info)
232
 
233
  with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp:
@@ -235,30 +235,30 @@ def main_interface(project_name, spotify_urls, include_all_info=True):
235
  final_filename = f"{project_name or 'spotify_tracks'}.xlsx"
236
  shutil.move(tmp.name, final_filename)
237
 
238
- print("✅ Proceso completado")
239
  return df, final_filename
240
 
241
- # Configuración de la Interfaz
242
  iface = gr.Interface(
243
  fn=main_interface,
244
  inputs=[
245
- gr.Textbox(label="Nombre del Proyecto", placeholder="Mi Colección Musical"),
246
  gr.Textbox(
247
- label="URLs de Spotify",
248
- placeholder="Pega URLs separadas por comas o saltos de línea (playlists, álbumes, canciones)...",
249
  lines=5
250
  ),
251
- gr.Checkbox(label="Incluir toda la información", value=True)
252
  ],
253
  outputs=[
254
- gr.Dataframe(label="Resultados"),
255
- gr.File(label="Descargar Excel")
256
  ],
257
  title="🎵 Spotify Track Collector PRO",
258
- description="Extrae información detallada de múltiples URLs de Spotify y genera un Excel unificado",
259
  examples=[
260
- ["Rock Clásico", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M, https://open.spotify.com/album/1R5BORZZxNUg8QMgbqt0nd", True],
261
- ["Éxitos Actuales", "https://open.spotify.com/playlist/37i9dQZEtDXc8QFRQ4qegR", False]
262
  ],
263
  allow_flagging="never",
264
  theme=gr.themes.Soft()
 
11
  client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')
12
 
13
  if not client_ids or not client_secrets:
14
+ raise ValueError("❌ Missing environment variables SPOTIFY_CLIENT_IDS or SPOTIFY_CLIENT_SECRETS")
15
 
16
  # Gestión de Rotación de Clientes
17
  current_client_index = 0
 
22
  global current_client_index, request_counter
23
  current_client_index = (current_client_index + 1) % len(client_ids)
24
  request_counter = 0
25
+ print(f"🔄 Rotating to Spotify client #{current_client_index + 1}")
26
 
27
  def get_spotify_token():
28
  global current_client_index
 
40
  if response.status_code == 200:
41
  return response.json().get('access_token')
42
 
43
+ print(f"❌ Error with client {current_client_index}: {response.text}")
44
  rotate_client()
45
 
46
+ raise Exception("🚨 All clients failed to obtain token")
47
 
48
  def make_spotify_request(url, params=None):
49
  global request_counter
 
55
  request_counter += 1
56
 
57
  if response.status_code == 429:
58
+ print(f"⚠️ Rate limit reached. Client: {current_client_index}")
59
  rotate_client()
60
+ time.sleep(int(response.headers.get('Retry-After', 10))) # Minimum wait of 10 seconds
61
  continue
62
 
63
  if response.status_code == 200:
 
71
  return None
72
 
73
  def extract_spotify_id(url, resource_type):
74
+ """Extracts ID from different Spotify URL formats"""
75
  clean_url = url.strip().split('?')[0].replace("https://open.spotify.com/", "")
76
 
77
+ # Handle URLs with /intl-xx/
78
  if "/intl-" in clean_url:
79
  parts = clean_url.split("/")
80
  return parts[-1]
 
93
  def get_playlist_tracks(playlist_url):
94
  playlist_id = extract_spotify_id(playlist_url, "playlist")
95
  if not playlist_id or len(playlist_id) != 22:
96
+ print(f"❌ Invalid playlist ID: {playlist_id}")
97
  return []
98
 
99
+ print(f"🎧 Getting playlist: {playlist_id}")
100
  all_tracks = []
101
  url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks'
102
  params = {'market': 'US', 'limit': 100}
 
109
  all_tracks.extend([item['track'] for item in data.get('items', []) if item.get('track')])
110
  url = data.get('next')
111
 
112
+ print(f"✅ Found {len(all_tracks)} tracks")
113
  return all_tracks
114
 
115
  def get_album_tracks(album_url):
116
  album_id = extract_spotify_id(album_url, "album")
117
  if not album_id or len(album_id) != 22:
118
+ print(f"❌ Invalid album ID: {album_id}")
119
  return []
120
 
121
+ print(f"💿 Getting album: {album_id}")
122
  all_tracks = []
123
  url = f'https://api.spotify.com/v1/albums/{album_id}/tracks'
124
  params = {'market': 'US', 'limit': 50}
 
153
  if track_data:
154
  all_tracks.append(track_data)
155
  except Exception as e:
156
+ print(f"⚠️ Error processing {url}: {str(e)}")
157
 
158
  return all_tracks
159
 
 
181
  duration_min = f"{track['duration_ms']//60000}:{str(track['duration_ms']%60000//1000).zfill(2)}"
182
 
183
  track_data = {
184
+ 'Artist': main_artist.get('name', 'Unknown'),
185
+ 'Title': track.get('name', 'No title'),
186
+ 'Album': track.get('album', {}).get('name', 'No album'),
187
  'ISRC': track.get('external_ids', {}).get('isrc', 'Not available'),
188
  'Popularity': track.get('popularity', 0),
189
  'Duration': duration_min,
 
205
 
206
  df = pd.DataFrame(processed)
207
 
208
+ # Remove duplicates using ISRC or artist-title combination
209
  df['dup_key'] = df.apply(
210
  lambda x: x['ISRC'] if x['ISRC'] != 'Not available' else f"{x['Artist']}|{x['Title']}",
211
  axis=1
 
215
  return df
216
 
217
  def main_interface(project_name, spotify_urls, include_all_info=True):
218
+ # Convert URLs separated by commas or line breaks
219
  urls = [url.strip() for url in spotify_urls.replace('\n', ',').split(',') if url.strip()]
220
 
221
  if not urls:
222
+ return pd.DataFrame({"Error": ["❌ Enter at least one valid URL"]}), None
223
 
224
+ print("⏳ Processing URLs...")
225
  tracks = process_tracks(urls)
226
 
227
  if not tracks:
228
+ return pd.DataFrame({"Error": ["❌ No tracks were found"]}), None
229
 
230
+ print("📊 Creating dataframe...")
231
  df = create_final_dataframe(tracks, include_all_info)
232
 
233
  with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp:
 
235
  final_filename = f"{project_name or 'spotify_tracks'}.xlsx"
236
  shutil.move(tmp.name, final_filename)
237
 
238
+ print("✅ Process completed")
239
  return df, final_filename
240
 
241
+ # Configuration of the Interface
242
  iface = gr.Interface(
243
  fn=main_interface,
244
  inputs=[
245
+ gr.Textbox(label="Project Name", placeholder="My Music Collection"),
246
  gr.Textbox(
247
+ label="Spotify URLs",
248
+ placeholder="Paste URLs separated by commas or line breaks (playlists, albums, songs)...",
249
  lines=5
250
  ),
251
+ gr.Checkbox(label="Include all information", value=True)
252
  ],
253
  outputs=[
254
+ gr.Dataframe(label="Results"),
255
+ gr.File(label="Download Excel")
256
  ],
257
  title="🎵 Spotify Track Collector PRO",
258
+ description="Extract detailed information from multiple Spotify URLs and generate a unified Excel file",
259
  examples=[
260
+ ["Classic Rock", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M, https://open.spotify.com/album/1R5BORZZxNUg8QMgbqt0nd", True],
261
+ ["Current Hits", "https://open.spotify.com/playlist/37i9dQZEtDXc8QFRQ4qegR", False]
262
  ],
263
  allow_flagging="never",
264
  theme=gr.themes.Soft()