File size: 4,484 Bytes
dbdd344
 
9faaa03
 
dbdd344
 
52a6c11
 
 
 
 
9faaa03
52a6c11
 
 
 
 
dbdd344
 
 
 
 
52a6c11
 
dbdd344
 
52a6c11
9faaa03
 
b414958
 
 
52a6c11
 
 
 
 
 
 
 
 
 
671016b
52a6c11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
671016b
dbdd344
52a6c11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9faaa03
 
b414958
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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"""
      <img src="{img}" width="300px" style="border-radius:10px;"/><br/>
      <strong>{pl_name}</strong> by {owner}<br/>
      {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"""
          <img src="{art}" width="200px" style="border-radius:8px;"/><br/>
          ▶️ <strong>{title}</strong><br/>
          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()