File size: 4,284 Bytes
dbdd344
 
9faaa03
 
dbdd344
 
52a6c11
 
9faaa03
52a6c11
 
 
 
 
dbdd344
 
 
 
 
52a6c11
 
dbdd344
 
52a6c11
9faaa03
 
b414958
 
 
52a6c11
 
f8df622
6c734a0
52a6c11
 
 
 
 
 
6c734a0
671016b
52a6c11
f8df622
52a6c11
 
f8df622
52a6c11
f8df622
52a6c11
 
 
 
 
f8df622
52a6c11
f8df622
52a6c11
 
f8df622
52a6c11
 
f8df622
52a6c11
f8df622
 
 
 
52a6c11
f8df622
52a6c11
 
f8df622
 
 
52a6c11
 
 
 
 
 
f8df622
 
 
52a6c11
 
 
 
f8df622
 
 
 
671016b
dbdd344
f8df622
6c734a0
 
 
 
f8df622
6c734a0
f8df622
 
 
52a6c11
 
f8df622
6c734a0
 
 
 
52a6c11
 
6c734a0
52a6c11
 
 
 
f8df622
 
 
 
 
 
52a6c11
f8df622
 
 
 
 
 
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

REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
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
    if not code:
        return gr.update(visible=False), gr.update(visible=False, choices=[])
    token = sp_oauth.get_access_token(code, as_dict=False)
    sp = spotipy.Spotify(auth=token)
    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: str):
    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 html, gr.update(visible=True)

def shuffle_and_play(pl_name: str):
    pid = user_playlists[pl_name]
    tracks, results = [], sp.playlist_tracks(pid)
    tracks.extend(results["items"])
    while results["next"]:
        results = sp.next(results)
        tracks.extend(results["items"])

    uris = [t["track"]["uri"] for t in tracks if t["track"]]
    devices = sp.devices()["devices"]
    if not devices:
        return gr.update(value="⚠️ No active device. Open Spotify and try again.", visible=True)

    sp.start_playback(device_id=devices[0]["id"], uris=uris)
    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 html
    return "▶️ Playing your shuffled playlist!"

with gr.Blocks() as demo:
    gr.Markdown("## 🎵 RNG Spotify Playlist Shuffler")
    gr.Markdown("Login, pick a playlist, then shuffle & play—all in one flow.")

    # Step 1: Login button using `link=` (Gradio ≥5.14.0)
    login_btn = gr.Button(
        "🔐 Step 1: Login to Spotify",
        link=get_auth_url()
    )

    # Hidden container for the ?code=… Spotify will append on redirect
    code_box  = gr.Textbox(visible=False, elem_id="auth_code")
    status    = gr.Markdown(visible=False)
    dropdown  = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
    info_html = gr.HTML(visible=False)
    shuffle_btn = gr.Button("🔀 Step 3: Shuffle & Play", visible=False)
    result      = gr.HTML(visible=False)

    # Run on every page-load: grab ?code=… via JS and call check_login
    demo.load(
        fn=check_login,
        inputs=[code_box],
        outputs=[status, dropdown],
        js="""
          const params = new URLSearchParams(window.location.search);
          const code = params.get("code");
          if (code) {
            document
              .getElementById("component-auth_code")
              .querySelector("textarea").value = code;
          }
        """
    )

    # When user picks a playlist, show its artwork/info and reveal the shuffle button
    dropdown.change(
        fn=load_playlist_info,
        inputs=[dropdown],
        outputs=[info_html, shuffle_btn]
    )

    # Shuffle & start playback, then show track info
    shuffle_btn.click(
        fn=shuffle_and_play,
        inputs=[dropdown],
        outputs=[result]
    )

if __name__ == "__main__":
    demo.launch()