Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
import requests
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
|
@@ -198,6 +198,22 @@ def get_artist_details(token, artist_id):
|
|
| 198 |
return response.json()
|
| 199 |
return None
|
| 200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
def extract_track_details(tracks, token):
|
| 202 |
"""Extract relevant information from track objects including artist details."""
|
| 203 |
tracks_info = []
|
|
@@ -299,94 +315,4 @@ def interface(project_name, spotify_urls, include_all_info=True):
|
|
| 299 |
|
| 300 |
print(f"Successfully authenticated with Spotify API")
|
| 301 |
|
| 302 |
-
all_tracks = []
|
| 303 |
-
|
| 304 |
-
# Process each URL
|
| 305 |
-
for url in valid_urls:
|
| 306 |
-
try:
|
| 307 |
-
print(f"Processing URL: {url}")
|
| 308 |
-
if "playlist" in url:
|
| 309 |
-
tracks = get_playlist_tracks(token_spotify, url)
|
| 310 |
-
# Add source information
|
| 311 |
-
for track in tracks:
|
| 312 |
-
track['playlist_source'] = url
|
| 313 |
-
all_tracks.extend(tracks)
|
| 314 |
-
elif "track" in url:
|
| 315 |
-
track = get_track_info(token_spotify, url)
|
| 316 |
-
if track:
|
| 317 |
-
track[0]['playlist_source'] = url
|
| 318 |
-
all_tracks.extend(track)
|
| 319 |
-
elif "album" in url:
|
| 320 |
-
album_tracks = get_album_tracks(token_spotify, url)
|
| 321 |
-
all_tracks.extend(album_tracks)
|
| 322 |
-
except Exception as e:
|
| 323 |
-
print(f"Error processing URL {url}: {str(e)}")
|
| 324 |
-
continue
|
| 325 |
-
|
| 326 |
-
if not all_tracks:
|
| 327 |
-
error_message = "Could not find any tracks in the provided URLs."
|
| 328 |
-
return gr.Dataframe(value=pd.DataFrame({"Error": [error_message]})), None
|
| 329 |
-
|
| 330 |
-
# Extract track details including artist information
|
| 331 |
-
print("Extracting detailed track information including ISRCs...")
|
| 332 |
-
tracks_info = extract_track_details(all_tracks, token_spotify)
|
| 333 |
-
|
| 334 |
-
# Remove duplicate tracks (based on ISRC or title+artist if ISRC not available)
|
| 335 |
-
print("Creating DataFrame and removing duplicates...")
|
| 336 |
-
df = pd.DataFrame(tracks_info)
|
| 337 |
-
|
| 338 |
-
# Create a key for deduplication
|
| 339 |
-
df['dedup_key'] = df.apply(
|
| 340 |
-
lambda row: row['isrc'] if row['isrc'] != 'Not available' else f"{row['artist']}_{row['title']}",
|
| 341 |
-
axis=1
|
| 342 |
-
)
|
| 343 |
-
|
| 344 |
-
# Drop duplicates
|
| 345 |
-
df = df.drop_duplicates(subset='dedup_key')
|
| 346 |
-
df = df.drop(columns=['dedup_key'])
|
| 347 |
-
|
| 348 |
-
print(f"Found {len(df)} unique tracks after deduplication")
|
| 349 |
-
|
| 350 |
-
# Filter columns if not include_all_info
|
| 351 |
-
if not include_all_info:
|
| 352 |
-
columns_to_keep = ['artist', 'title', 'isrc', 'album', 'genres', 'release_date', 'track_popularity', 'explicit', 'spotify_url']
|
| 353 |
-
df = df[columns_to_keep]
|
| 354 |
-
|
| 355 |
-
# Save DataFrame to an Excel file
|
| 356 |
-
tmpfile = NamedTemporaryFile(delete=False, suffix='.xlsx')
|
| 357 |
-
df.to_excel(tmpfile.name, index=False)
|
| 358 |
-
|
| 359 |
-
# Rename the file with the project name
|
| 360 |
-
project_file_name = f"{project_name}.xlsx"
|
| 361 |
-
shutil.move(tmpfile.name, project_file_name)
|
| 362 |
-
|
| 363 |
-
return df, project_file_name
|
| 364 |
-
|
| 365 |
-
# Gradio Interface Configuration
|
| 366 |
-
iface = gr.Interface(
|
| 367 |
-
fn=interface,
|
| 368 |
-
inputs=[
|
| 369 |
-
gr.Textbox(label="Project Name", placeholder="Enter a name for your export"),
|
| 370 |
-
gr.Textbox(
|
| 371 |
-
label="Spotify URLs (Tracks, Albums or Playlists)",
|
| 372 |
-
placeholder="Enter one Spotify URL per line (tracks, albums or playlists)",
|
| 373 |
-
lines=5
|
| 374 |
-
),
|
| 375 |
-
gr.Checkbox(label="Include All Track Information", value=True)
|
| 376 |
-
],
|
| 377 |
-
outputs=[
|
| 378 |
-
gr.Dataframe(),
|
| 379 |
-
gr.File(label="Download Excel")
|
| 380 |
-
],
|
| 381 |
-
title="Spotify Track Collector",
|
| 382 |
-
description="Extract tracks from multiple Spotify playlists, albums, and tracks into a single Excel file.",
|
| 383 |
-
examples=[
|
| 384 |
-
["Pop Collection", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M\nhttps://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT", True],
|
| 385 |
-
["Rock Collection", "https://open.spotify.com/playlist/37i9dQZF1DWXRqgorJj26U", False],
|
| 386 |
-
["Album Tracks", "https://open.spotify.com/album/1R5BORZZxNUg8QMgbqt0nd", True]
|
| 387 |
-
],
|
| 388 |
-
allow_flagging="never"
|
| 389 |
-
)
|
| 390 |
-
|
| 391 |
-
if __name__ == "__main__":
|
| 392 |
-
iface.launch()
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
import requests
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
|
|
|
| 198 |
return response.json()
|
| 199 |
return None
|
| 200 |
|
| 201 |
+
def get_track_isrc(token, track):
|
| 202 |
+
"""Get ISRC code for a track if not already present."""
|
| 203 |
+
if track.get('external_ids', {}).get('isrc'):
|
| 204 |
+
return track['external_ids']['isrc']
|
| 205 |
+
|
| 206 |
+
# If track doesn't have ISRC, try to get it from the API
|
| 207 |
+
if track.get('id'):
|
| 208 |
+
headers = {'Authorization': f'Bearer {token}'}
|
| 209 |
+
url = f'https://api.spotify.com/v1/tracks/{track["id"]}'
|
| 210 |
+
|
| 211 |
+
response = make_request_with_retry(url, headers)
|
| 212 |
+
if response and response.json().get('external_ids', {}).get('isrc'):
|
| 213 |
+
return response.json()['external_ids']['isrc']
|
| 214 |
+
|
| 215 |
+
return 'Not available'
|
| 216 |
+
|
| 217 |
def extract_track_details(tracks, token):
|
| 218 |
"""Extract relevant information from track objects including artist details."""
|
| 219 |
tracks_info = []
|
|
|
|
| 315 |
|
| 316 |
print(f"Successfully authenticated with Spotify API")
|
| 317 |
|
| 318 |
+
all_tracks = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|