import os import gradio as gr import spotipy from spotipy.oauth2 import SpotifyOAuth import random # 1. Hard‐code your redirect URI here: REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/" # 2. Keep your client creds in Secrets, as before: CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"] CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"] SCOPE = ( "user-read-playback-state " "user-modify-playback-state " "playlist-read-private" ) sp_oauth = SpotifyOAuth( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, redirect_uri=REDIRECT_URI, scope=SCOPE, show_dialog=True, ) sp = None user_playlists = {} def get_auth_url(): return sp_oauth.get_authorize_url() def check_login(code: str): global sp, user_playlists token = sp_oauth.get_access_token(code, as_dict=False) sp = spotipy.Spotify(auth=token) # pull their first 50 playlists pls = sp.current_user_playlists(limit=50)["items"] user_playlists = {p["name"]: p["id"] for p in pls} return ( gr.update(visible=True, value="✅ Logged in! Choose a playlist below."), gr.update(visible=True, choices=list(user_playlists.keys())) ) def load_playlist_info(pl_name): pid = user_playlists[pl_name] data = sp.playlist(pid) img = data["images"][0]["url"] if data["images"] else "" owner = data["owner"]["display_name"] desc = data.get("description", "") html = f"""
{pl_name} by {owner}
{desc} """ return gr.update(visible=True, value=html), gr.update(visible=True) def shuffle_and_play(pl_name): pid = user_playlists[pl_name] # grab all tracks tracks, results = [], sp.playlist_tracks(pid) tracks += results["items"] while results["next"]: results = sp.next(results) tracks += results["items"] uris = [t["track"]["uri"] for t in tracks if t["track"]] random.shuffle(uris) # send to their first active device devs = sp.devices()["devices"] if not devs: return gr.update(value="⚠️ No active Spotify device found. Start Spotify on one of your devices.", visible=True) sp.start_playback(device_id=devs[0]["id"], uris=uris) # show the first shuffled track’s info: now = sp.current_playback() if now and now.get("item"): it = now["item"] art = it["album"]["images"][0]["url"] title = it["name"] artists = ", ".join(a["name"] for a in it["artists"]) html = f"""
▶️ {title}
by {artists} """ return gr.update(value=html, visible=True) return gr.update(value="▶️ Playing your shuffled playlist!", visible=True) with gr.Blocks() as demo: gr.Markdown("## 🎵 RNG Spotify Playlist Shuffler") gr.Markdown("Login, pick a playlist, then shuffle & play—all in one flow.") # 1. Launch the login page login_btn = gr.Button("🔐 Step 1: Login to Spotify") login_btn.click( lambda: get_auth_url(), None, None, _js="(url) => window.open(url, '_blank')" ) # 2. Hidden “code” container (we’ll fill it automatically via JS) code_box = gr.Textbox(visible=False, elem_id="auth_code") # 3. When we have a code, finish the OAuth step… status = gr.Markdown(visible=False) demo.load( # run on every page‐load fn=check_login, inputs=[code_box], outputs=[status, gr.State()], _js=""" // on-load JS: grab ?code= from URL and stuff it into the hidden box const p = new URLSearchParams(window.location.search); const c = p.get("code"); if(c) { document .getElementById("component-auth_code") .querySelector("textarea").value = c; } """ ) # 4. Playlist dropdown + info dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False) info_html = gr.HTML(visible=False) dropdown.change(load_playlist_info, [dropdown], [info_html, gr.update(dropdown, visible=True)]) # 5. Shuffle & play result = gr.HTML(visible=False) shuffle_btn = gr.Button("🔀 Step 3: Shuffle & Play", visible=False) shuffle_btn.click(shuffle_and_play, [dropdown], [result]) if __name__ == "__main__": demo.launch()