Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,21 +1,19 @@
|
|
| 1 |
-
|
| 2 |
import requests
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
| 5 |
import shutil
|
|
|
|
| 6 |
import os
|
| 7 |
from tempfile import NamedTemporaryFile
|
|
|
|
| 8 |
|
| 9 |
# Spotify API credentials from environment variables
|
| 10 |
-
client_ids = os.getenv("SPOTIFY_CLIENT_IDS"
|
| 11 |
-
client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS"
|
| 12 |
|
| 13 |
-
# For testing/demo purposes only - DO NOT use in production
|
| 14 |
if not client_ids or not client_secrets:
|
| 15 |
-
|
| 16 |
-
# Provide fake credentials for demo purposes
|
| 17 |
-
client_ids = "demo_client_id"
|
| 18 |
-
client_secrets = "demo_client_secret"
|
| 19 |
|
| 20 |
client_ids = client_ids.split(',')
|
| 21 |
client_secrets = client_secrets.split(',')
|
|
@@ -26,28 +24,16 @@ total_requests = 0
|
|
| 26 |
|
| 27 |
# Spotify Functions
|
| 28 |
def get_token(client_id, client_secret):
|
| 29 |
-
"""Get Spotify API token. Returns a demo token in case of failure for testing."""
|
| 30 |
url = 'https://accounts.spotify.com/api/token'
|
| 31 |
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
| 32 |
payload = {'grant_type': 'client_credentials'}
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
print("Successfully obtained Spotify API token")
|
| 41 |
-
return response.json().get('access_token')
|
| 42 |
-
else:
|
| 43 |
-
print(f"Error getting token: {response.status_code} - {response.text}")
|
| 44 |
-
# For demo/testing only - simulate a token
|
| 45 |
-
if client_id == "demo_client_id":
|
| 46 |
-
print("Using demo token for testing purposes")
|
| 47 |
-
return "demo_token"
|
| 48 |
-
return None
|
| 49 |
-
except Exception as e:
|
| 50 |
-
print(f"Exception during token retrieval: {str(e)}")
|
| 51 |
return None
|
| 52 |
|
| 53 |
def handle_rate_limit(response, attempt):
|
|
@@ -328,25 +314,99 @@ def interface(project_name, spotify_urls, include_all_info=True):
|
|
| 328 |
# Get token
|
| 329 |
token_spotify = get_token(client_ids[current_api_index], client_secrets[current_api_index])
|
| 330 |
if not token_spotify:
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
# In demo mode, return sample data
|
| 334 |
-
demo_data = get_demo_data()
|
| 335 |
-
df = pd.DataFrame(demo_data)
|
| 336 |
-
|
| 337 |
-
# Save DataFrame to an Excel file
|
| 338 |
-
tmpfile = NamedTemporaryFile(delete=False, suffix='.xlsx')
|
| 339 |
-
df.to_excel(tmpfile.name, index=False)
|
| 340 |
-
|
| 341 |
-
# Rename the file with the project name
|
| 342 |
-
project_file_name = f"{project_name}.xlsx"
|
| 343 |
-
shutil.move(tmpfile.name, project_file_name)
|
| 344 |
-
|
| 345 |
-
return df, project_file_name
|
| 346 |
-
else:
|
| 347 |
-
error_message = "Failed to authenticate with Spotify API. Please try again later."
|
| 348 |
-
return gr.Dataframe(value=pd.DataFrame({"Error": [error_message]})), None
|
| 349 |
|
| 350 |
print(f"Successfully authenticated with Spotify API")
|
| 351 |
|
| 352 |
-
all_tracks = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
import requests
|
| 3 |
import pandas as pd
|
| 4 |
import time
|
| 5 |
import shutil
|
| 6 |
+
import numpy as np
|
| 7 |
import os
|
| 8 |
from tempfile import NamedTemporaryFile
|
| 9 |
+
from openpyxl import Workbook
|
| 10 |
|
| 11 |
# Spotify API credentials from environment variables
|
| 12 |
+
client_ids = os.getenv("SPOTIFY_CLIENT_IDS")
|
| 13 |
+
client_secrets = os.getenv("SPOTIFY_CLIENT_SECRETS")
|
| 14 |
|
|
|
|
| 15 |
if not client_ids or not client_secrets:
|
| 16 |
+
raise ValueError("SPOTIFY_CLIENT_IDS or SPOTIFY_CLIENT_SECRETS environment variables not set.")
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
client_ids = client_ids.split(',')
|
| 19 |
client_secrets = client_secrets.split(',')
|
|
|
|
| 24 |
|
| 25 |
# Spotify Functions
|
| 26 |
def get_token(client_id, client_secret):
|
|
|
|
| 27 |
url = 'https://accounts.spotify.com/api/token'
|
| 28 |
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
|
| 29 |
payload = {'grant_type': 'client_credentials'}
|
| 30 |
+
response = requests.post(url, headers=headers, data=payload, auth=(client_id, client_secret))
|
| 31 |
+
global total_requests
|
| 32 |
+
total_requests += 1
|
| 33 |
+
if response.status_code == 200:
|
| 34 |
+
return response.json().get('access_token')
|
| 35 |
+
else:
|
| 36 |
+
print(f"Error getting token: {response.status_code} - {response.text}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
return None
|
| 38 |
|
| 39 |
def handle_rate_limit(response, attempt):
|
|
|
|
| 314 |
# Get token
|
| 315 |
token_spotify = get_token(client_ids[current_api_index], client_secrets[current_api_index])
|
| 316 |
if not token_spotify:
|
| 317 |
+
error_message = "Failed to authenticate with Spotify API. Please try again later."
|
| 318 |
+
return gr.Dataframe(value=pd.DataFrame({"Error": [error_message]})), None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 319 |
|
| 320 |
print(f"Successfully authenticated with Spotify API")
|
| 321 |
|
| 322 |
+
all_tracks = []
|
| 323 |
+
|
| 324 |
+
# Process each URL
|
| 325 |
+
for url in valid_urls:
|
| 326 |
+
try:
|
| 327 |
+
print(f"Processing URL: {url}")
|
| 328 |
+
if "playlist" in url:
|
| 329 |
+
tracks = get_playlist_tracks(token_spotify, url)
|
| 330 |
+
# Add source information
|
| 331 |
+
for track in tracks:
|
| 332 |
+
track['playlist_source'] = url
|
| 333 |
+
all_tracks.extend(tracks)
|
| 334 |
+
elif "track" in url:
|
| 335 |
+
track = get_track_info(token_spotify, url)
|
| 336 |
+
if track:
|
| 337 |
+
track[0]['playlist_source'] = url
|
| 338 |
+
all_tracks.extend(track)
|
| 339 |
+
elif "album" in url:
|
| 340 |
+
album_tracks = get_album_tracks(token_spotify, url)
|
| 341 |
+
all_tracks.extend(album_tracks)
|
| 342 |
+
except Exception as e:
|
| 343 |
+
print(f"Error processing URL {url}: {str(e)}")
|
| 344 |
+
continue
|
| 345 |
+
|
| 346 |
+
if not all_tracks:
|
| 347 |
+
error_message = "Could not find any tracks in the provided URLs."
|
| 348 |
+
return gr.Dataframe(value=pd.DataFrame({"Error": [error_message]})), None
|
| 349 |
+
|
| 350 |
+
# Extract track details including artist information
|
| 351 |
+
print("Extracting detailed track information including ISRCs...")
|
| 352 |
+
tracks_info = extract_track_details(all_tracks, token_spotify)
|
| 353 |
+
|
| 354 |
+
# Remove duplicate tracks (based on ISRC or title+artist if ISRC not available)
|
| 355 |
+
print("Creating DataFrame and removing duplicates...")
|
| 356 |
+
df = pd.DataFrame(tracks_info)
|
| 357 |
+
|
| 358 |
+
# Create a key for deduplication
|
| 359 |
+
df['dedup_key'] = df.apply(
|
| 360 |
+
lambda row: row['isrc'] if row['isrc'] != 'Not available' else f"{row['artist']}_{row['title']}",
|
| 361 |
+
axis=1
|
| 362 |
+
)
|
| 363 |
+
|
| 364 |
+
# Drop duplicates
|
| 365 |
+
df = df.drop_duplicates(subset='dedup_key')
|
| 366 |
+
df = df.drop(columns=['dedup_key'])
|
| 367 |
+
|
| 368 |
+
print(f"Found {len(df)} unique tracks after deduplication")
|
| 369 |
+
|
| 370 |
+
# Filter columns if not include_all_info
|
| 371 |
+
if not include_all_info:
|
| 372 |
+
columns_to_keep = ['artist', 'title', 'isrc', 'album', 'genres', 'release_date', 'track_popularity', 'explicit', 'spotify_url']
|
| 373 |
+
df = df[columns_to_keep]
|
| 374 |
+
|
| 375 |
+
# Save DataFrame to an Excel file
|
| 376 |
+
tmpfile = NamedTemporaryFile(delete=False, suffix='.xlsx')
|
| 377 |
+
df.to_excel(tmpfile.name, index=False)
|
| 378 |
+
|
| 379 |
+
# Rename the file with the project name
|
| 380 |
+
project_file_name = f"{project_name}.xlsx"
|
| 381 |
+
shutil.move(tmpfile.name, project_file_name)
|
| 382 |
+
|
| 383 |
+
return df, project_file_name
|
| 384 |
+
|
| 385 |
+
# Gradio Interface Configuration
|
| 386 |
+
iface = gr.Interface(
|
| 387 |
+
fn=interface,
|
| 388 |
+
inputs=[
|
| 389 |
+
gr.Textbox(label="Project Name", placeholder="Enter a name for your export"),
|
| 390 |
+
gr.Textbox(
|
| 391 |
+
label="Spotify URLs (Tracks, Albums or Playlists)",
|
| 392 |
+
placeholder="Enter one Spotify URL per line (tracks, albums or playlists)",
|
| 393 |
+
lines=5
|
| 394 |
+
),
|
| 395 |
+
gr.Checkbox(label="Include All Track Information", value=True)
|
| 396 |
+
],
|
| 397 |
+
outputs=[
|
| 398 |
+
gr.Dataframe(),
|
| 399 |
+
gr.File(label="Download Excel")
|
| 400 |
+
],
|
| 401 |
+
title="Spotify Track Collector",
|
| 402 |
+
description="Extract tracks from multiple Spotify playlists, albums, and tracks into a single Excel file.",
|
| 403 |
+
examples=[
|
| 404 |
+
["Pop Collection", "https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M\nhttps://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT", True],
|
| 405 |
+
["Rock Collection", "https://open.spotify.com/playlist/37i9dQZF1DWXRqgorJj26U", False],
|
| 406 |
+
["Album Tracks", "https://open.spotify.com/album/1R5BORZZxNUg8QMgbqt0nd", True]
|
| 407 |
+
],
|
| 408 |
+
allow_flagging="never"
|
| 409 |
+
)
|
| 410 |
+
|
| 411 |
+
if __name__ == "__main__":
|
| 412 |
+
iface.launch()
|