Mthrfkr commited on
Commit
e9370c5
·
verified ·
1 Parent(s): e0ba68f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +100 -101
app.py CHANGED
@@ -1,3 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
  import requests
3
  import pandas as pd
@@ -6,6 +19,10 @@ import shutil
6
  import os
7
  from tempfile import NamedTemporaryFile
8
 
 
 
 
 
9
  # Configuración de Credenciales
10
  client_ids = os.getenv("SPOTIFY_CLIENT_IDS", "").split(',')
11
  client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')
@@ -26,23 +43,23 @@ def rotate_client():
26
 
27
  def get_spotify_token():
28
  global current_client_index
29
- for intento in range(len(client_ids)):
30
- client_id = client_ids[current_client_index]
31
- client_secret = client_secrets[current_client_index]
32
- print(f"🔑 Intentando token con cliente #{current_client_index + 1}")
33
- response = requests.post(
34
  'https://accounts.spotify.com/api/token',
35
  headers={'Content-Type': 'application/x-www-form-urlencoded'},
36
  data={'grant_type': 'client_credentials'},
37
- auth=(client_id, client_secret)
38
  )
39
- print(f"➡️ get_spotify_token: status_code={response.status_code}")
40
- if response.status_code == 200:
41
- token = response.json().get('access_token')
42
  print(f"✅ Token OK (cliente #{current_client_index+1}): {token[:10]}…")
43
  return token
44
  else:
45
- print(f"❌ Error token cliente #{current_client_index+1}: {response.text}")
46
  rotate_client()
47
  raise Exception("🚨 All clients failed to obtain token")
48
 
@@ -54,132 +71,116 @@ def make_spotify_request(url, params=None):
54
  if params:
55
  print(f" con params: {params}")
56
  headers = {'Authorization': f'Bearer {token}'}
57
-
58
  for intento in range(3):
59
- print(f"🔁 make_spotify_request intento #{intento+1}")
60
- response = requests.get(url, headers=headers, params=params)
61
- print(f"➡️ Status code: {response.status_code}")
62
  request_counter += 1
63
-
64
- if response.status_code == 429:
65
- retry = int(response.headers.get('Retry-After', 10))
66
- print(f"⚠️ Rate limit. Esperando {retry}s y rotando cliente")
67
  rotate_client()
68
  time.sleep(retry)
69
  continue
70
-
71
- if response.status_code == 200:
72
  if request_counter >= MAX_REQUESTS_PER_CLIENT:
73
- print("🔄 Límite requests alcanzado, rotando cliente")
74
  rotate_client()
75
- return response.json()
76
-
77
- print(f"❌ Error {response.status_code}: {response.text}")
78
  time.sleep(2)
79
-
80
- print("🚫 make_spotify_request: todos los intentos fallaron")
81
  return None
82
 
83
  def extract_spotify_id(url, resource_type):
84
  clean = url.strip().split('?')[0].replace("https://open.spotify.com/", "")
85
  if "/intl-" in clean:
86
- parts = clean.split("/")
87
- return parts[-1]
88
  parts = clean.split("/")
89
  try:
90
- idx = parts.index(resource_type)
91
- return parts[idx + 1]
92
  except ValueError:
93
- for part in parts:
94
- if len(part) == 22 and resource_type in url:
95
- return part
96
- print(f"❌ extract_spotify_id no pudo extraer ID de {url}")
97
  return None
98
 
99
  def get_playlist_tracks(playlist_url):
100
  pid = extract_spotify_id(playlist_url, "playlist")
101
- if not pid:
102
- return []
103
  print(f"🎧 Getting playlist: {pid}")
104
  tracks = []
105
- url = f'https://api.spotify.com/v1/playlists/{pid}/tracks'
106
- params = {'market': 'US', 'limit': 100}
107
-
108
  while url:
109
  data = make_spotify_request(url, params)
110
- if not data:
111
- break
112
- items = data.get('items', [])
113
- print(f" Got {len(items)} items")
114
- tracks.extend([it['track'] for it in items if it.get('track')])
115
  url = data.get('next')
116
- print(f"✅ Found total {len(tracks)} tracks in playlist")
117
  return tracks
118
 
119
  def get_album_tracks(album_url):
120
  aid = extract_spotify_id(album_url, "album")
121
- if not aid:
122
- return []
123
  print(f"💿 Getting album: {aid}")
124
- all_tracks = []
125
- url = f'https://api.spotify.com/v1/albums/{aid}/tracks'
126
- params = {'market': 'US', 'limit': 50}
127
-
128
  while url:
129
- data = make_spotify_request(url, params)
130
- if not data:
131
- break
132
- for item in data.get('items', []):
133
- print(f" Fetching track detail for {item['id']}")
134
- td = make_spotify_request(f"https://api.spotify.com/v1/tracks/{item['id']}")
135
- if td:
136
- all_tracks.append(td)
137
- url = data.get('next')
138
- print(f"✅ Found total {len(all_tracks)} tracks in album")
139
- return all_tracks
140
 
141
  def process_tracks(urls):
142
  print("🔍 process_tracks iniciado")
143
- all_tracks = []
144
- for url in urls:
145
- print(f"➡️ Procesando URL: {url}")
146
  try:
147
- if "playlist" in url:
148
- all_tracks.extend(get_playlist_tracks(url))
149
- elif "album" in url:
150
- all_tracks.extend(get_album_tracks(url))
151
- elif "track" in url:
152
- tid = extract_spotify_id(url, "track")
153
  td = make_spotify_request(f"https://api.spotify.com/v1/tracks/{tid}")
154
- if td:
155
- all_tracks.append(td)
156
  except Exception as e:
157
- print(f"⚠️ Error procesando {url}: {e}")
158
- print(f"🔍 process_tracks terminó con {len(all_tracks)} tracks")
159
- return all_tracks
160
 
161
  def create_final_dataframe(tracks, include_all_info=True):
162
  print("📊 create_final_dataframe iniciado")
163
- artist_cache = {}
164
- def get_artist_details(aid):
165
- if aid not in artist_cache:
166
- print(f" Obteniendo detalles de artista {aid}")
167
  d = make_spotify_request(f"https://api.spotify.com/v1/artists/{aid}")
168
- artist_cache[aid] = {
169
- 'genres': d.get('genres', []) if d else [],
170
- 'followers': d.get('followers', {}).get('total', 0) if d else 0,
171
- 'popularity': d.get('popularity', 0) if d else 0
172
  }
173
- return artist_cache[aid]
174
-
175
  rows = []
176
  for tr in tracks:
177
- if not tr:
178
- continue
179
  ma = tr['artists'][0] if tr.get('artists') else {}
180
- ai = get_artist_details(ma.get('id')) if ma.get('id') else {}
181
  dur = f"{tr['duration_ms']//60000}:{str(tr['duration_ms']%60000//1000).zfill(2)}"
182
- row = {
183
  'Artist': ma.get('name','Unknown'),
184
  'Title': tr.get('name','No title'),
185
  'Album': tr.get('album',{}).get('name',''),
@@ -190,7 +191,7 @@ def create_final_dataframe(tracks, include_all_info=True):
190
  'Spotify URI': tr.get('external_urls',{}).get('spotify','')
191
  }
192
  if include_all_info:
193
- row.update({
194
  'Genres': ', '.join(ai.get('genres',[])),
195
  'Artist Followers': ai.get('followers',0),
196
  'Artist Popularity': ai.get('popularity',0),
@@ -198,21 +199,19 @@ def create_final_dataframe(tracks, include_all_info=True):
198
  'Track ID': tr.get('id'),
199
  'Album ID': tr.get('album',{}).get('id')
200
  })
201
- rows.append(row)
202
  df = pd.DataFrame(rows)
203
- df['dup_key'] = df.apply(
204
- lambda x: x['ISRC'] or f"{x['Artist']}|{x['Title']}", axis=1
205
- )
206
  df = df.drop_duplicates('dup_key').drop(columns='dup_key')
207
  print("📊 create_final_dataframe completado")
208
  return df
209
 
210
  def main_interface(project_name, spotify_urls, include_all_info=True):
211
- print(f"\n🎬 Inicio interface con proyecto: {project_name}")
212
  urls = [u.strip() for u in spotify_urls.replace('\n',',').split(',') if u.strip()]
213
  if not urls:
214
  print("❌ No hay URLs válidas")
215
- return pd.DataFrame({"Error":["❌ Ingresa al menos una URL"]}), None
216
  tracks = process_tracks(urls)
217
  if not tracks:
218
  print("❌ No se encontraron tracks")
@@ -220,10 +219,10 @@ def main_interface(project_name, spotify_urls, include_all_info=True):
220
  df = create_final_dataframe(tracks, include_all_info)
221
  with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp:
222
  df.to_excel(tmp.name, index=False)
223
- filename = f"{project_name or 'spotify_tracks'}.xlsx"
224
- shutil.move(tmp.name, filename)
225
- print(f"✅ Proceso completado. Archivo: {filename}\n")
226
- return df, filename
227
 
228
  # Configuración de la interfaz
229
  iface = gr.Interface(
 
1
+ # —————— PARCHE GRADIO_CLIENT BOOLEANS ——————
2
+ import gradio_client.utils as client_utils
3
+
4
+ _original_get_type = client_utils.get_type
5
+ def patched_get_type(schema):
6
+ # Si el schema no es dict (e.g. un bool), devolvemos Any pa' que no truene
7
+ if not isinstance(schema, dict):
8
+ return "Any"
9
+ return _original_get_type(schema)
10
+
11
+ client_utils.get_type = patched_get_type
12
+ # ————————————————————————————————
13
+
14
  import gradio as gr
15
  import requests
16
  import pandas as pd
 
19
  import os
20
  from tempfile import NamedTemporaryFile
21
 
22
+ # Imprime versión pa' checar que ya cargue Gradio correcto
23
+ import gradio as _gr
24
+ print("⚙️ Gradio version cargada:", _gr.__version__)
25
+
26
  # Configuración de Credenciales
27
  client_ids = os.getenv("SPOTIFY_CLIENT_IDS", "").split(',')
28
  client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')
 
43
 
44
  def get_spotify_token():
45
  global current_client_index
46
+ for _ in range(len(client_ids)):
47
+ cid = client_ids[current_client_index]
48
+ csec = client_secrets[current_client_index]
49
+ print(f"🔑 Intentando token con cliente #{current_client_index+1}")
50
+ resp = requests.post(
51
  'https://accounts.spotify.com/api/token',
52
  headers={'Content-Type': 'application/x-www-form-urlencoded'},
53
  data={'grant_type': 'client_credentials'},
54
+ auth=(cid, csec)
55
  )
56
+ print(f"➡️ get_spotify_token status={resp.status_code}")
57
+ if resp.status_code == 200:
58
+ token = resp.json().get('access_token')
59
  print(f"✅ Token OK (cliente #{current_client_index+1}): {token[:10]}…")
60
  return token
61
  else:
62
+ print(f"❌ Error token cliente #{current_client_index+1}: {resp.text}")
63
  rotate_client()
64
  raise Exception("🚨 All clients failed to obtain token")
65
 
 
71
  if params:
72
  print(f" con params: {params}")
73
  headers = {'Authorization': f'Bearer {token}'}
 
74
  for intento in range(3):
75
+ print(f"🔁 intento #{intento+1}")
76
+ r = requests.get(url, headers=headers, params=params)
77
+ print(f"➡️ Status code: {r.status_code}")
78
  request_counter += 1
79
+ if r.status_code == 429:
80
+ retry = int(r.headers.get('Retry-After', 10))
81
+ print(f"⚠️ Rate limit, espero {retry}s y rotamos cliente")
 
82
  rotate_client()
83
  time.sleep(retry)
84
  continue
85
+ if r.status_code == 200:
 
86
  if request_counter >= MAX_REQUESTS_PER_CLIENT:
87
+ print("🔄 Límite alcanzado, roto cliente")
88
  rotate_client()
89
+ return r.json()
90
+ print(f"❌ Error {r.status_code}: {r.text}")
 
91
  time.sleep(2)
92
+ print("🚫 make_spotify_request: fallaron los 3 intentos")
 
93
  return None
94
 
95
  def extract_spotify_id(url, resource_type):
96
  clean = url.strip().split('?')[0].replace("https://open.spotify.com/", "")
97
  if "/intl-" in clean:
98
+ return clean.split("/")[-1]
 
99
  parts = clean.split("/")
100
  try:
101
+ i = parts.index(resource_type)
102
+ return parts[i+1]
103
  except ValueError:
104
+ for p in parts:
105
+ if len(p)==22 and resource_type in url:
106
+ return p
107
+ print(f"❌ extract_spotify_id no pudo extraer de {url}")
108
  return None
109
 
110
  def get_playlist_tracks(playlist_url):
111
  pid = extract_spotify_id(playlist_url, "playlist")
112
+ if not pid: return []
 
113
  print(f"🎧 Getting playlist: {pid}")
114
  tracks = []
115
+ url = f"https://api.spotify.com/v1/playlists/{pid}/tracks"
116
+ params = {'market':'US','limit':100}
 
117
  while url:
118
  data = make_spotify_request(url, params)
119
+ if not data: break
120
+ items = data.get('items',[])
121
+ print(f" Recibí {len(items)} items")
122
+ tracks += [it['track'] for it in items if it.get('track')]
 
123
  url = data.get('next')
124
+ print(f"✅ Found {len(tracks)} tracks")
125
  return tracks
126
 
127
  def get_album_tracks(album_url):
128
  aid = extract_spotify_id(album_url, "album")
129
+ if not aid: return []
 
130
  print(f"💿 Getting album: {aid}")
131
+ all_t = []
132
+ url = f"https://api.spotify.com/v1/albums/{aid}/tracks"
133
+ params = {'market':'US','limit':50}
 
134
  while url:
135
+ d = make_spotify_request(url, params)
136
+ if not d: break
137
+ for it in d.get('items',[]):
138
+ print(f" Detail track {it['id']}")
139
+ td = make_spotify_request(f"https://api.spotify.com/v1/tracks/{it['id']}")
140
+ if td: all_t.append(td)
141
+ url = d.get('next')
142
+ print(f"✅ Found {len(all_t)} tracks")
143
+ return all_t
 
 
144
 
145
  def process_tracks(urls):
146
  print("🔍 process_tracks iniciado")
147
+ all_t = []
148
+ for u in urls:
149
+ print(f"➡️ Procesando {u}")
150
  try:
151
+ if "playlist" in u:
152
+ all_t += get_playlist_tracks(u)
153
+ elif "album" in u:
154
+ all_t += get_album_tracks(u)
155
+ elif "track" in u:
156
+ tid = extract_spotify_id(u, "track")
157
  td = make_spotify_request(f"https://api.spotify.com/v1/tracks/{tid}")
158
+ if td: all_t.append(td)
 
159
  except Exception as e:
160
+ print(f"⚠️ Error en {u}: {e}")
161
+ print(f"🔍 process_tracks terminó con {len(all_t)} tracks")
162
+ return all_t
163
 
164
  def create_final_dataframe(tracks, include_all_info=True):
165
  print("📊 create_final_dataframe iniciado")
166
+ cache = {}
167
+ def get_artist(aid):
168
+ if aid not in cache:
169
+ print(f" Artist details {aid}")
170
  d = make_spotify_request(f"https://api.spotify.com/v1/artists/{aid}")
171
+ cache[aid] = {
172
+ 'genres':d.get('genres',[]) if d else [],
173
+ 'followers':d.get('followers',{}).get('total',0) if d else 0,
174
+ 'popularity':d.get('popularity',0) if d else 0
175
  }
176
+ return cache[aid]
 
177
  rows = []
178
  for tr in tracks:
179
+ if not tr: continue
 
180
  ma = tr['artists'][0] if tr.get('artists') else {}
181
+ ai = get_artist(ma.get('id')) if ma.get('id') else {}
182
  dur = f"{tr['duration_ms']//60000}:{str(tr['duration_ms']%60000//1000).zfill(2)}"
183
+ base = {
184
  'Artist': ma.get('name','Unknown'),
185
  'Title': tr.get('name','No title'),
186
  'Album': tr.get('album',{}).get('name',''),
 
191
  'Spotify URI': tr.get('external_urls',{}).get('spotify','')
192
  }
193
  if include_all_info:
194
+ base.update({
195
  'Genres': ', '.join(ai.get('genres',[])),
196
  'Artist Followers': ai.get('followers',0),
197
  'Artist Popularity': ai.get('popularity',0),
 
199
  'Track ID': tr.get('id'),
200
  'Album ID': tr.get('album',{}).get('id')
201
  })
202
+ rows.append(base)
203
  df = pd.DataFrame(rows)
204
+ df['dup_key'] = df.apply(lambda x: x['ISRC'] or f"{x['Artist']}|{x['Title']}", axis=1)
 
 
205
  df = df.drop_duplicates('dup_key').drop(columns='dup_key')
206
  print("📊 create_final_dataframe completado")
207
  return df
208
 
209
  def main_interface(project_name, spotify_urls, include_all_info=True):
210
+ print(f"\n🎬 Inicio interface proyecto: {project_name}")
211
  urls = [u.strip() for u in spotify_urls.replace('\n',',').split(',') if u.strip()]
212
  if not urls:
213
  print("❌ No hay URLs válidas")
214
+ return pd.DataFrame({"Error":["❌ Ingresa al menos una URL válida"]}), None
215
  tracks = process_tracks(urls)
216
  if not tracks:
217
  print("❌ No se encontraron tracks")
 
219
  df = create_final_dataframe(tracks, include_all_info)
220
  with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp:
221
  df.to_excel(tmp.name, index=False)
222
+ fname = f"{project_name or 'spotify_tracks'}.xlsx"
223
+ shutil.move(tmp.name, fname)
224
+ print(f"✅ Proceso completado. Archivo: {fname}\n")
225
+ return df, fname
226
 
227
  # Configuración de la interfaz
228
  iface = gr.Interface(