Mthrfkr commited on
Commit
06b1a06
Β·
verified Β·
1 Parent(s): 743ebae

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -128
app.py CHANGED
@@ -1,161 +1,66 @@
1
- # β€”β€”β€”β€”β€”β€” PARCHE rΓ‘pido para bug de gradio_client β€”β€”β€”β€”β€”β€”
2
- import gradio_client.utils as _cu
3
- _original = _cu.get_type
4
- def _patched_get_type(schema):
5
- # Si no es dict (p.ej. bool) devolvemos Any para que no explote
6
- if not isinstance(schema, dict):
7
- return "Any"
8
- return _original(schema)
9
- _cu.get_type = _patched_get_type
10
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
11
-
12
-
13
-
14
  import os
15
  import requests
16
- import pandas as pd
17
  import gradio as gr
18
- from tempfile import NamedTemporaryFile
19
- import shutil
20
 
21
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
22
- # 1️⃣ Config de Spotify
23
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
24
  CLIENT_ID = os.getenv("SPOTIFY_CLIENT_IDS", "").split(',')[0]
25
  CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')[0]
26
- TOKEN_CACHE = None
27
 
28
  def get_token():
29
- """Pide un token Client Credentials y lo cachea."""
30
- global TOKEN_CACHE
31
- if TOKEN_CACHE:
32
- return TOKEN_CACHE
33
  resp = requests.post(
34
  "https://accounts.spotify.com/api/token",
35
  data={"grant_type":"client_credentials"},
36
  auth=(CLIENT_ID, CLIENT_SECRET),
37
  )
38
  resp.raise_for_status()
39
- TOKEN_CACHE = resp.json()["access_token"]
40
- return TOKEN_CACHE
41
 
42
  def extract_pid(url):
43
- """Saca el ID limpio de la URL."""
44
  return url.strip().rstrip('/').split('/')[-1].split('?')[0]
45
 
46
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
47
- # 2️⃣ Funciones core
48
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
49
- def is_public_playlist(pid):
50
- """Chequea metadata: devuelve (True, nombre, total) o (False, mensaje, None)."""
 
51
  token = get_token()
 
 
 
 
52
  r = requests.get(
53
  f"https://api.spotify.com/v1/playlists/{pid}",
54
- headers={"Authorization":f"Bearer {token}"}
55
  )
56
- if r.status_code == 200:
57
- j = r.json()
58
- return True, j["name"], j["tracks"]["total"]
59
- else:
60
- return False, f"no pΓΊblica / error {r.status_code}", None
61
-
62
- def fetch_all_tracks(pid, sample_limit=None):
63
- """
64
- Trae todos los tracks de la playlist en una lista de dicts.
65
- Si sample_limit estΓ‘ definido, sΓ³lo jala esa cantidad (para demo).
66
- """
67
- token = get_token()
68
- url = f"https://api.spotify.com/v1/playlists/{pid}/tracks"
69
- params = {"limit":100, "market":"US"}
70
- all_t = []
71
- while url:
72
- r = requests.get(url, headers={"Authorization":f"Bearer {token}"}, params=params)
73
- r.raise_for_status()
74
- data = r.json()
75
- items = data.get("items", [])
76
- for it in items:
77
- tr = it.get("track")
78
- if tr:
79
- all_t.append({
80
- "Artist": tr["artists"][0]["name"],
81
- "Title": tr["name"],
82
- "Album": tr["album"]["name"],
83
- "Duration_ms": tr["duration_ms"],
84
- "Popularity": tr["popularity"],
85
- "Explicit": tr["explicit"],
86
- "Track ID": tr["id"],
87
- })
88
- if sample_limit and len(all_t) >= sample_limit:
89
- return all_t
90
- url = data.get("next")
91
- return all_t
92
-
93
- def build_dataframe(tracks, include_all):
94
- """Convierte la lista de tracks en un DataFrame y limpia duplicados."""
95
- df = pd.DataFrame(tracks)
96
- # Ejemplo de columnita extra si include_all
97
- if include_all:
98
- df["Duration_min"] = df["Duration_ms"].floordiv(60000).astype(str) + ":" + (df["Duration_ms"]%60000//1000).astype(str).str.zfill(2)
99
- # Quitamos dupes por Track ID
100
- return df.drop_duplicates("Track ID", ignore_index=True)
101
-
102
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
103
- # 3️⃣ FunciΓ³n principal
104
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
105
- def main(project_name, urls_text, include_all):
106
- urls = [u for u in urls_text.replace("\n",",").split(",") if u.strip()]
107
- if not urls:
108
- return pd.DataFrame({"Error":["❌ Pon al menos una URL vÑlida"]}), None
109
-
110
- resultado = []
111
- logs = []
112
- for url in urls:
113
- pid = extract_pid(url)
114
- ok, nombre, total = is_public_playlist(pid)
115
- if not ok:
116
- logs.append(f"⚠️ {pid}: {nombre}")
117
- continue
118
- logs.append(f"βœ… {pid}: β€œ{nombre}” ({total} tracks)")
119
- # Para demo sample_limit=5, quita sample_limit para todo
120
- tracks = fetch_all_tracks(pid, sample_limit=None)
121
- resultado.extend(tracks)
122
-
123
- if not resultado:
124
- return pd.DataFrame({"Error":logs}), None
125
-
126
- df = build_dataframe(resultado, include_all)
127
- # Generar Excel
128
- with NamedTemporaryFile(delete=False, suffix=".xlsx") as tmp:
129
- df.to_excel(tmp.name, index=False)
130
- fname = f"{project_name or 'spotify_tracks'}.xlsx"
131
- shutil.move(tmp.name, fname)
132
-
133
- # Metemos los logs al final del DF (opcional)
134
- df_logs = pd.DataFrame({"Logs": logs})
135
- return df, fname
136
 
137
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
138
- # 4️⃣ Interfaz Gradio
139
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
140
  iface = gr.Interface(
141
- fn=main,
142
- inputs=[
143
- gr.Textbox(label="Nombre del proyecto"),
144
- gr.Textbox(label="URLs de Spotify (coma o salto de lΓ­nea)", lines=4),
145
- gr.Checkbox(label="Incluir info extra", value=True),
146
- ],
147
- outputs=[
148
- gr.Dataframe(label="Resultados"),
149
- gr.File(label="Descargar Excel"),
150
- ],
151
- title="🎡 Spotify Track Collector PRO",
152
- description="SΓ³lo pull playlists pΓΊblicas. Salta las demΓ‘s.",
153
- examples=[
154
- ["Mi Playlist Verano", "https://open.spotify.com/playlist/13QBKWGO2VY1pc1RJz91YN", True],
155
- ],
156
- allow_flagging="never",
157
- theme=gr.themes.Soft(),
158
  )
159
 
160
- if __name__=="__main__":
161
  iface.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import requests
 
3
  import gradio as gr
 
 
4
 
5
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
6
+ # Config Spotify (Client Credentials)
7
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
8
  CLIENT_ID = os.getenv("SPOTIFY_CLIENT_IDS", "").split(',')[0]
9
  CLIENT_SECRET = os.getenv("SPOTIFY_CLIENT_SECRETS", "").split(',')[0]
 
10
 
11
  def get_token():
12
+ """Pide token con Client Credentials."""
 
 
 
13
  resp = requests.post(
14
  "https://accounts.spotify.com/api/token",
15
  data={"grant_type":"client_credentials"},
16
  auth=(CLIENT_ID, CLIENT_SECRET),
17
  )
18
  resp.raise_for_status()
19
+ return resp.json()["access_token"]
 
20
 
21
  def extract_pid(url):
22
+ """Extrae el ID de playlist de la URL."""
23
  return url.strip().rstrip('/').split('/')[-1].split('?')[0]
24
 
25
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
26
+ # FunciΓ³n POC
27
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
28
+ def fetch_public_playlist(url):
29
+ if not CLIENT_ID or not CLIENT_SECRET:
30
+ return "❌ SPOTIFY_CLIENT_IDS o CLIENT_SECRETS faltantes"
31
  token = get_token()
32
+ pid = extract_pid(url)
33
+ if len(pid) != 22:
34
+ return f"❌ ID invÑlido: '{pid}'"
35
+ # Metadata
36
  r = requests.get(
37
  f"https://api.spotify.com/v1/playlists/{pid}",
38
+ headers={"Authorization": f"Bearer {token}"}
39
  )
40
+ if r.status_code != 200:
41
+ return f"❌ No pública o error {r.status_code}"
42
+ info = r.json()
43
+ name = info.get("name", "?")
44
+ total = info.get("tracks", {}).get("total", "?")
45
+ # Sample de tracks (limit 5)
46
+ items = requests.get(
47
+ f"https://api.spotify.com/v1/playlists/{pid}/tracks",
48
+ headers={"Authorization": f"Bearer {token}"},
49
+ params={"limit": 5}
50
+ ).json().get("items", [])
51
+ titles = [it["track"]["name"] for it in items if it.get("track")]
52
+ return f"βœ… β€œ{name}”: {total} tracks\n🎡 Muestra: {titles}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
55
+ # Interfaz Gradio
56
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
57
  iface = gr.Interface(
58
+ fn=fetch_public_playlist,
59
+ inputs=gr.Textbox(label="URL de playlist"),
60
+ outputs="text",
61
+ title="πŸ”Ž Checa playlist pΓΊblica",
62
+ description="SΓ³lo playlists pΓΊblicas con Client Credentials"
 
 
 
 
 
 
 
 
 
 
 
 
63
  )
64
 
65
+ if __name__ == "__main__":
66
  iface.launch(server_name="0.0.0.0", server_port=7860)