jisaacso219 commited on
Commit
2082b5c
Β·
verified Β·
1 Parent(s): 702b499

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +96 -27
app.py CHANGED
@@ -1,13 +1,24 @@
1
  import os
 
2
  import gradio as gr
3
  import spotipy
4
  from spotipy.oauth2 import SpotifyOAuth
5
  import random
6
 
 
 
7
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
 
 
 
 
 
 
 
 
 
8
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
9
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
10
- SCOPE = "user-read-playback-state user-modify-playback-state playlist-read-private"
11
 
12
  sp_oauth = SpotifyOAuth(
13
  client_id=CLIENT_ID,
@@ -24,82 +35,140 @@ def get_auth_url():
24
  return sp_oauth.get_authorize_url()
25
 
26
  def check_login(code: str):
 
 
 
 
 
27
  if not code:
 
28
  return gr.update(visible=False), gr.update(visible=False, choices=[])
29
- token = sp_oauth.get_access_token(code, as_dict=False)
30
- global sp, user_playlists
31
- sp = spotipy.Spotify(auth=token)
 
 
 
32
  pls = sp.current_user_playlists(limit=50)["items"]
33
  user_playlists = {p["name"]: p["id"] for p in pls}
 
 
 
 
34
  return (
35
- gr.update(visible=True, value="βœ… Logged in! Choose a playlist below."),
36
  gr.update(visible=True, choices=list(user_playlists.keys())),
37
  )
38
 
39
- def load_playlist_info(pl_name):
40
  pid = user_playlists[pl_name]
41
  data = sp.playlist(pid)
42
  img = data["images"][0]["url"] if data["images"] else ""
43
  owner = data["owner"]["display_name"]
44
  desc = data.get("description", "")
45
- html = f"""<img src="{img}" width="300"/><br/>
46
- <strong>{pl_name}</strong> by {owner}<br/>{desc}"""
 
 
47
  return html, gr.update(visible=True)
48
 
49
- def shuffle_and_play(pl_name):
50
- pid = user_playlists[pl_name]
 
51
  tracks, results = [], sp.playlist_tracks(pid)
52
  tracks.extend(results["items"])
53
  while results["next"]:
54
  results = sp.next(results)
55
  tracks.extend(results["items"])
56
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
57
- devs = sp.devices()["devices"]
58
- if not devs:
59
- return gr.update(value="⚠️ No active Spotify device.", visible=True)
60
- sp.start_playback(device_id=devs[0]["id"], uris=uris)
61
- now = sp.current_playback()
62
- if now and now.get("item"):
63
- it = now["item"]
64
- art = it["album"]["images"][0]["url"]
65
- title = it["name"]
66
- artists = ", ".join(a["name"] for a in it["artists"])
67
- return f"""<img src="{art}" width="200"/><br/>
68
- ▢️ <strong>{title}</strong><br/>by {artists}"""
69
- return "▢️ Playing your shuffled playlist!"
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  with gr.Blocks() as demo:
 
72
  gr.Markdown("""
73
- ⚠️ **View this Space in its own tab!**
74
- Click the πŸ”— icon at top-right before logging in.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  """)
76
 
 
77
  login_btn = gr.Button(
78
  "πŸ” Step 1: Login to Spotify",
79
  link=get_auth_url()
80
  )
81
 
 
82
  code_box = gr.Textbox(visible=False, elem_id="auth_code")
 
 
83
  status = gr.Markdown(visible=False)
84
  dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
 
 
85
  info_html = gr.HTML(visible=False)
86
  shuffle_btn = gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
87
  result = gr.HTML(visible=False)
88
 
 
89
  demo.load(
90
  fn=check_login,
91
  inputs=[code_box],
92
  outputs=[status, dropdown],
93
  js="""
94
  () => {
95
- return new URLSearchParams(window.location.search).get('code') || "";
 
96
  }
97
  """
98
  )
99
 
 
100
  dropdown.change(load_playlist_info, [dropdown], [info_html, shuffle_btn])
 
 
101
  shuffle_btn.click(shuffle_and_play, [dropdown], [result])
102
 
103
  if __name__ == "__main__":
104
  demo.launch()
105
-
 
1
  import os
2
+ import json
3
  import gradio as gr
4
  import spotipy
5
  from spotipy.oauth2 import SpotifyOAuth
6
  import random
7
 
8
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
9
+ # 1) Redirect URI (must match your Spotify Dashboard)
10
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
11
+
12
+ # 2) Scopes now include `streaming`
13
+ SCOPE = (
14
+ "streaming "
15
+ "user-read-playback-state "
16
+ "user-modify-playback-state "
17
+ "playlist-read-private"
18
+ )
19
+
20
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
21
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
 
22
 
23
  sp_oauth = SpotifyOAuth(
24
  client_id=CLIENT_ID,
 
35
  return sp_oauth.get_authorize_url()
36
 
37
  def check_login(code: str):
38
+ """
39
+ Called on page‐load (demo.load). Exchanges the `code` for an access token,
40
+ then writes that token into window.ACCESS_TOKEN for the SDK.
41
+ """
42
+ global sp, user_playlists
43
  if not code:
44
+ # Wait for the redirect with ?code=
45
  return gr.update(visible=False), gr.update(visible=False, choices=[])
46
+ # Exchange for token (as_dict so we can grab the raw access_token)
47
+ tokinfo = sp_oauth.get_access_token(code, as_dict=True)
48
+ access_token = tokinfo["access_token"]
49
+ sp = spotipy.Spotify(auth=access_token)
50
+
51
+ # Fetch playlists
52
  pls = sp.current_user_playlists(limit=50)["items"]
53
  user_playlists = {p["name"]: p["id"] for p in pls}
54
+
55
+ # Embed a script to set window.ACCESS_TOKEN for the Web Playback SDK
56
+ js_token = f"<script>window.ACCESS_TOKEN = '{access_token}';</script>"
57
+
58
  return (
59
+ gr.update(visible=True, value="βœ… Logged in! Choose a playlist below." + js_token),
60
  gr.update(visible=True, choices=list(user_playlists.keys())),
61
  )
62
 
63
+ def load_playlist_info(pl_name: str):
64
  pid = user_playlists[pl_name]
65
  data = sp.playlist(pid)
66
  img = data["images"][0]["url"] if data["images"] else ""
67
  owner = data["owner"]["display_name"]
68
  desc = data.get("description", "")
69
+ html = f"""
70
+ <img src="{img}" width="300px" style="border-radius:10px;"/><br/>
71
+ <strong>{pl_name}</strong> by {owner}<br/>{desc}
72
+ """
73
  return html, gr.update(visible=True)
74
 
75
+ def shuffle_and_play(pl_name: str):
76
+ pid = user_playlists[pl_name]
77
+ # Gather + shuffle URIs
78
  tracks, results = [], sp.playlist_tracks(pid)
79
  tracks.extend(results["items"])
80
  while results["next"]:
81
  results = sp.next(results)
82
  tracks.extend(results["items"])
83
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
84
+ random.shuffle(uris)
85
+
86
+ # Generate a JS snippet that kicks off playback via the Web Playback SDK
87
+ uris_json = json.dumps(uris)
88
+ player_js = f"""
89
+ <script>
90
+ (async () => {{
91
+ const token = window.ACCESS_TOKEN;
92
+ const device_id = window._webDeviceId;
93
+ console.log("▢️ Playing on", device_id);
94
+ await fetch(
95
+ 'https://api.spotify.com/v1/me/player/play?device_id=' + device_id,
96
+ {{
97
+ method: 'PUT',
98
+ headers: {{
99
+ 'Authorization': 'Bearer ' + token,
100
+ 'Content-Type': 'application/json'
101
+ }},
102
+ body: JSON.stringify({{ uris: {uris_json} }})
103
+ }}
104
+ );
105
+ }})();
106
+ </script>
107
+ """
108
+ return gr.update(value="▢️ Now playing in‐browser!" + player_js, visible=True)
109
 
110
  with gr.Blocks() as demo:
111
+ # Instruction to open in standalone tab
112
  gr.Markdown("""
113
+ ⚠️ **Please open this Space in its own tab** (click the πŸ”— icon top-right)
114
+ so the OAuth flow and embedded player can work correctly.
115
+ """)
116
+
117
+ # Inject the Web Playback SDK
118
+ gr.HTML("""
119
+ <script src="https://sdk.scdn.co/spotify-player.js"></script>
120
+ <script>
121
+ window.onSpotifyWebPlaybackSDKReady = () => {
122
+ window._player = new Spotify.Player({
123
+ name: 'RNG Web Player',
124
+ getOAuthToken: cb => { cb(window.ACCESS_TOKEN); },
125
+ volume: 0.5
126
+ });
127
+ _player.addListener('ready', ({ device_id }) => {
128
+ console.log('🟒 Web Playback ready, device_id:', device_id);
129
+ window._webDeviceId = device_id;
130
+ });
131
+ _player.connect();
132
+ };
133
+ </script>
134
  """)
135
 
136
+ # 1️⃣ Login
137
  login_btn = gr.Button(
138
  "πŸ” Step 1: Login to Spotify",
139
  link=get_auth_url()
140
  )
141
 
142
+ # Hidden box for the OAuth `code`
143
  code_box = gr.Textbox(visible=False, elem_id="auth_code")
144
+
145
+ # 2️⃣ Playlist selection
146
  status = gr.Markdown(visible=False)
147
  dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
148
+
149
+ # 3️⃣ Playlist info & shuffle
150
  info_html = gr.HTML(visible=False)
151
  shuffle_btn = gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
152
  result = gr.HTML(visible=False)
153
 
154
+ # On page-load: grab `?code=` and run check_login
155
  demo.load(
156
  fn=check_login,
157
  inputs=[code_box],
158
  outputs=[status, dropdown],
159
  js="""
160
  () => {
161
+ const c = new URLSearchParams(window.location.search).get('code') || "";
162
+ return c;
163
  }
164
  """
165
  )
166
 
167
+ # Show playlist info once selected
168
  dropdown.change(load_playlist_info, [dropdown], [info_html, shuffle_btn])
169
+
170
+ # Shuffle & play in-browser
171
  shuffle_btn.click(shuffle_and_play, [dropdown], [result])
172
 
173
  if __name__ == "__main__":
174
  demo.launch()