Mthrfkr commited on
Commit
88e83f7
·
verified ·
1 Parent(s): af7e719

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -59
app.py CHANGED
@@ -22,99 +22,107 @@ 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"🔄 Rotating to Spotify client #{current_client_index + 1}")
26
 
27
  def get_spotify_token():
28
  global current_client_index
29
- for _ in range(len(client_ids)):
30
  client_id = client_ids[current_client_index]
31
  client_secret = client_secrets[current_client_index]
32
-
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
-
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
50
  token = get_spotify_token()
 
 
 
 
51
  headers = {'Authorization': f'Bearer {token}'}
52
 
53
- for _ in range(3):
 
54
  response = requests.get(url, headers=headers, params=params)
 
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)))
61
  continue
62
-
63
  if response.status_code == 200:
64
  if request_counter >= MAX_REQUESTS_PER_CLIENT:
 
65
  rotate_client()
66
  return response.json()
67
 
68
  print(f"❌ Error {response.status_code}: {response.text}")
69
  time.sleep(2)
70
 
 
71
  return None
72
 
73
  def extract_spotify_id(url, resource_type):
74
- clean_url = url.strip().split('?')[0].replace("https://open.spotify.com/", "")
75
- if "/intl-" in clean_url:
76
- parts = clean_url.split("/")
77
  return parts[-1]
78
- parts = clean_url.split("/")
79
  try:
80
  idx = parts.index(resource_type)
81
- return parts[idx + 1] if idx + 1 < len(parts) else None
82
  except ValueError:
83
  for part in parts:
84
  if len(part) == 22 and resource_type in url:
85
  return part
86
- return None
 
87
 
88
  def get_playlist_tracks(playlist_url):
89
- playlist_id = extract_spotify_id(playlist_url, "playlist")
90
- if not playlist_id or len(playlist_id) != 22:
91
- print(f"❌ Invalid playlist ID: {playlist_id}")
92
  return []
93
-
94
- print(f"🎧 Getting playlist: {playlist_id}")
95
  tracks = []
96
- url = f'https://api.spotify.com/v1/playlists/{playlist_id}/tracks'
97
  params = {'market': 'US', 'limit': 100}
98
 
99
  while url:
100
  data = make_spotify_request(url, params)
101
  if not data:
102
  break
103
- tracks.extend([item['track'] for item in data.get('items', []) if item.get('track')])
 
 
104
  url = data.get('next')
105
-
106
- print(f"✅ Found {len(tracks)} tracks")
107
  return tracks
108
 
109
  def get_album_tracks(album_url):
110
- album_id = extract_spotify_id(album_url, "album")
111
- if not album_id or len(album_id) != 22:
112
- print(f"❌ Invalid album ID: {album_id}")
113
  return []
114
-
115
- print(f"💿 Getting album: {album_id}")
116
  all_tracks = []
117
- url = f'https://api.spotify.com/v1/albums/{album_id}/tracks'
118
  params = {'market': 'US', 'limit': 50}
119
 
120
  while url:
@@ -122,17 +130,19 @@ def get_album_tracks(album_url):
122
  if not data:
123
  break
124
  for item in data.get('items', []):
 
125
  td = make_spotify_request(f"https://api.spotify.com/v1/tracks/{item['id']}")
126
  if td:
127
  all_tracks.append(td)
128
  url = data.get('next')
129
-
130
- print(f"✅ Encontrados {len(all_tracks)} tracks")
131
  return all_tracks
132
 
133
  def process_tracks(urls):
 
134
  all_tracks = []
135
  for url in urls:
 
136
  try:
137
  if "playlist" in url:
138
  all_tracks.extend(get_playlist_tracks(url))
@@ -144,13 +154,16 @@ def process_tracks(urls):
144
  if td:
145
  all_tracks.append(td)
146
  except Exception as e:
147
- print(f"⚠️ Error processing {url}: {e}")
 
148
  return all_tracks
149
 
150
  def create_final_dataframe(tracks, include_all_info=True):
 
151
  artist_cache = {}
152
  def get_artist_details(aid):
153
  if aid not in artist_cache:
 
154
  d = make_spotify_request(f"https://api.spotify.com/v1/artists/{aid}")
155
  artist_cache[aid] = {
156
  'genres': d.get('genres', []) if d else [],
@@ -166,49 +179,50 @@ def create_final_dataframe(tracks, include_all_info=True):
166
  ma = tr['artists'][0] if tr.get('artists') else {}
167
  ai = get_artist_details(ma.get('id')) if ma.get('id') else {}
168
  dur = f"{tr['duration_ms']//60000}:{str(tr['duration_ms']%60000//1000).zfill(2)}"
169
- base = {
170
- 'Artist': ma.get('name', 'Unknown'),
171
- 'Title': tr.get('name', 'No title'),
172
- 'Album': tr.get('album', {}).get('name', 'No album'),
173
- 'ISRC': tr.get('external_ids', {}).get('isrc', 'Not available'),
174
- 'Popularity': tr.get('popularity', 0),
175
  'Duration': dur,
176
- 'Release Date': tr.get('album', {}).get('release_date', 'Not available'),
177
- 'Spotify URI': tr.get('external_urls', {}).get('spotify', '')
178
  }
179
  if include_all_info:
180
- base.update({
181
- 'Genres': ', '.join(ai.get('genres', [])),
182
- 'Artist Followers': ai.get('followers', 0),
183
- 'Artist Popularity': ai.get('popularity', 0),
184
  'Explicit': 'Yes' if tr.get('explicit') else 'No',
185
  'Track ID': tr.get('id'),
186
- 'Album ID': tr.get('album', {}).get('id')
187
  })
188
- rows.append(base)
189
-
190
  df = pd.DataFrame(rows)
191
  df['dup_key'] = df.apply(
192
- lambda x: x['ISRC'] if x['ISRC'] != 'Not available' else f"{x['Artist']}|{x['Title']}", axis=1
193
  )
194
  df = df.drop_duplicates('dup_key').drop(columns='dup_key')
 
195
  return df
196
 
197
  def main_interface(project_name, spotify_urls, include_all_info=True):
198
- urls = [u.strip() for u in spotify_urls.replace('\n', ',').split(',') if u.strip()]
 
199
  if not urls:
200
- return pd.DataFrame({"Error": ["❌ Debes ingresar al menos una URL válida"]}), None
201
- print("⏳ Processing URLs...")
202
  tracks = process_tracks(urls)
203
  if not tracks:
204
- return pd.DataFrame({"Error": ["❌ No se encontraron tracks"]}), None
205
- print("📊 Creating dataframe...")
206
  df = create_final_dataframe(tracks, include_all_info)
207
  with NamedTemporaryFile(delete=False, suffix='.xlsx') as tmp:
208
  df.to_excel(tmp.name, index=False)
209
  filename = f"{project_name or 'spotify_tracks'}.xlsx"
210
  shutil.move(tmp.name, filename)
211
- print("✅ Process completed")
212
  return df, filename
213
 
214
  # Configuración de la interfaz
 
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"🔄 Rotated to Spotify client #{current_client_index + 1}")
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
 
49
  def make_spotify_request(url, params=None):
50
  global request_counter
51
  token = get_spotify_token()
52
+ print(f"🔑 Usando token: {token[:10]}…")
53
+ print(f"🌐 Llamando a URL: {url}")
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:
 
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))
 
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 [],
 
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',''),
186
+ 'ISRC': tr.get('external_ids',{}).get('isrc',''),
187
+ 'Popularity': tr.get('popularity',0),
188
  'Duration': dur,
189
+ 'Release Date': tr.get('album',{}).get('release_date',''),
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),
197
  'Explicit': 'Yes' if tr.get('explicit') else 'No',
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")
219
+ return pd.DataFrame({"Error":["❌ No se encontraron tracks"]}), None
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