jisaacso219 commited on
Commit
6645382
Β·
verified Β·
1 Parent(s): 52c1c26

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -102
app.py CHANGED
@@ -5,15 +5,10 @@ import gradio as gr
5
  import spotipy
6
  from spotipy.oauth2 import SpotifyOAuth
7
 
8
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
9
- # 1) Spotify credentials (in Hugging Face Secrets)
10
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
11
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
 
12
 
13
- # 2) This must match exactly in your Spotify Dashboard
14
- REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
15
-
16
- # 3) Include `streaming` for the Web Playback SDK
17
  SCOPE = (
18
  "streaming "
19
  "user-read-playback-state "
@@ -21,7 +16,6 @@ SCOPE = (
21
  "playlist-read-private"
22
  )
23
 
24
- # Spotify OAuth helper
25
  sp_oauth = SpotifyOAuth(
26
  client_id=CLIENT_ID,
27
  client_secret=CLIENT_SECRET,
@@ -37,59 +31,44 @@ def get_auth_url():
37
  return sp_oauth.get_authorize_url()
38
 
39
  def check_login(code: str):
40
- """
41
- Called via demo.load on every page-load.
42
- When `code` is non-empty, exchanges it, fetches playlists,
43
- and injects the Web Playback SDK + token + iframe-bust.
44
- """
45
  global sp, user_playlists
46
-
47
- # still waiting for Spotify to redirect back…
48
  if not code:
49
  return (
50
- gr.update(visible=False), # status message
51
- gr.update(visible=False), # playlist dropdown
52
- gr.update(visible=False), # SDK injection HTML
53
  )
54
 
55
- # exchange code for token
56
- tokinfo = sp_oauth.get_access_token(code, as_dict=True)
57
  access_token = tokinfo["access_token"]
58
  sp = spotipy.Spotify(auth=access_token)
59
 
60
- # fetch first 50 playlists
61
  items = sp.current_user_playlists(limit=50)["items"]
62
  user_playlists = {p["name"]: p["id"] for p in items}
63
 
64
- # inject Web Playback SDK + debug scripts + iframe bust
65
  sdk_js = f"""
66
- <script>
67
- // bust out of HF iframe if still sand-boxed
68
- if (window.self !== window.top) {{
69
- window.top.location.href = window.location.href;
70
- }}
71
- console.log("[SDK] ACCESS_TOKEN set");
72
- window.ACCESS_TOKEN = "{access_token}";
73
- </script>
74
- <script src="https://sdk.scdn.co/spotify-player.js"></script>
75
- <script>
76
- window.onSpotifyWebPlaybackSDKReady = () => {{
77
- console.log("[SDK] SDK Ready");
78
- const player = new Spotify.Player({{
79
- name: 'RNG Web Player',
80
- getOAuthToken: cb => cb(window.ACCESS_TOKEN),
81
- volume: 0.5
82
- }});
83
- ['initialization_error','authentication_error','account_error','playback_error']
84
- .forEach(evt => player.addListener(evt, e => console.error(`[SDK ${evt}]`, e)));
85
- player.addListener('ready', ({ device_id }) => {{
86
- console.log('[SDK] device_id:', device_id);
87
- window._webDeviceId = device_id;
88
- }});
89
- player.connect().then(ok => console.log('[SDK] connect()', ok));
90
- }};
91
- </script>
92
- """
93
 
94
  return (
95
  gr.update(visible=True, value="βœ… Logged in! Select a playlist below."),
@@ -104,87 +83,63 @@ def load_playlist_info(playlist_name: str):
104
  owner= data["owner"]["display_name"]
105
  desc = data.get("description","")
106
  html = f"""
107
- <img src="{img}" width="300" style="border-radius:8px;"/><br/>
108
  <strong>{playlist_name}</strong> by {owner}<br/>{desc}
109
  """
110
  return html, gr.update(visible=True)
111
 
112
  def shuffle_and_play(playlist_name: str):
113
  pid = user_playlists[playlist_name]
114
- # gather tracks
115
  tracks, res = [], sp.playlist_tracks(pid)
116
  tracks.extend(res["items"])
117
  while res["next"]:
118
  res = sp.next(res)
119
  tracks.extend(res["items"])
120
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
121
- random.shuffle(uris) # your RNG shuffle
122
 
123
  uris_json = json.dumps(uris)
124
  play_js = f"""
125
- <div id="player_debug" style="color:white;font-family:monospace;"></div>
126
- <script>
127
- console.log("[JS] play→", window._webDeviceId, {len(uris)}, "URIs");
128
- (async () => {{
129
- try {{
130
- const resp = await fetch(
131
- 'https://api.spotify.com/v1/me/player/play?device_id=' + window._webDeviceId,
132
- {{
133
- method: 'PUT',
134
- headers: {{
135
- 'Authorization': 'Bearer ' + window.ACCESS_TOKEN,
136
- 'Content-Type': 'application/json'
137
- }},
138
- body: JSON.stringify({{ uris: {uris_json} }})
139
- }}
140
- );
141
- const text = await resp.text();
142
- console.log("[JS] status:", resp.status, text);
143
- document.getElementById("player_debug").innerText =
144
- `[JS] status: ${{resp.status}} – ${{text}}`;
145
- }} catch(e) {{
146
- console.error("[JS] Playback error:", e);
147
- document.getElementById("player_debug").innerText =
148
- "[JS] Playback error: " + e;
149
- }}
150
- }})();
151
- </script>
152
- """
153
  return gr.update(value="▢️ Now playing in-browser!" + play_js, visible=True)
154
 
155
  with gr.Blocks() as demo:
156
- # 0) iframe-bust on initial load
157
  gr.HTML("""
158
- <script>
159
- if (window.self !== window.top) {
160
- window.top.location.href = window.location.href;
161
- }
162
- </script>
163
- """)
164
- # 0b) fallback standalone link
165
- gr.HTML('<a href="https://jisaacso219-rng-shuffle.hf.space/" target="_blank">'
166
- 'πŸ”— Open in standalone tab</a>')
167
-
168
- gr.Markdown("**1)** Login β†’ **2)** Pick a playlist β†’ **3)** Shuffle & Play in-browser")
169
-
170
- # Step 1: Login in the same tab
171
  login_btn = gr.Button("πŸ” Step 1: Login to Spotify")
172
  login_btn.click(
173
  fn=None, inputs=None, outputs=None,
174
  js=f"() => window.location.href = '{get_auth_url()}'"
175
  )
176
 
177
- # State & UI placeholders
178
- code_state = gr.State() # receives the OAuth `code`
179
- status = gr.Markdown(visible=False)
180
- playlist_dd= gr.Dropdown([], label="Step 2: Select a Playlist", visible=False)
181
- sdk_html = gr.HTML(visible=False)
182
 
183
- info_html = gr.HTML(visible=False)
184
- shuffle_btn= gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
185
- result = gr.HTML(visible=False)
186
 
187
- # On page-load (or after redirect), grab `code` and run check_login
188
  demo.load(
189
  fn=check_login,
190
  inputs=[code_state],
@@ -197,3 +152,4 @@ with gr.Blocks() as demo:
197
 
198
  if __name__ == "__main__":
199
  demo.launch(server_name="0.0.0.0", ssr_mode=False)
 
 
5
  import spotipy
6
  from spotipy.oauth2 import SpotifyOAuth
7
 
 
 
8
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
9
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
10
+ REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
11
 
 
 
 
 
12
  SCOPE = (
13
  "streaming "
14
  "user-read-playback-state "
 
16
  "playlist-read-private"
17
  )
18
 
 
19
  sp_oauth = SpotifyOAuth(
20
  client_id=CLIENT_ID,
21
  client_secret=CLIENT_SECRET,
 
31
  return sp_oauth.get_authorize_url()
32
 
33
  def check_login(code: str):
 
 
 
 
 
34
  global sp, user_playlists
 
 
35
  if not code:
36
  return (
37
+ gr.update(visible=False),
38
+ gr.update(visible=False),
39
+ gr.update(visible=False),
40
  )
41
 
42
+ tokinfo = sp_oauth.get_access_token(code, as_dict=True)
 
43
  access_token = tokinfo["access_token"]
44
  sp = spotipy.Spotify(auth=access_token)
45
 
 
46
  items = sp.current_user_playlists(limit=50)["items"]
47
  user_playlists = {p["name"]: p["id"] for p in items}
48
 
 
49
  sdk_js = f"""
50
+ <script>
51
+ window.ACCESS_TOKEN = "{access_token}";
52
+ if (window.self !== window.top) {{
53
+ window.top.location.href = window.location.href;
54
+ }}
55
+ </script>
56
+ <script src="https://sdk.scdn.co/spotify-player.js"></script>
57
+ <script>
58
+ window.onSpotifyWebPlaybackSDKReady = () => {{
59
+ const player = new Spotify.Player({{
60
+ name: 'RNG Web Player',
61
+ getOAuthToken: cb => cb(window.ACCESS_TOKEN),
62
+ volume: 0.5
63
+ }});
64
+ player.addListener('ready', ({ device_id }) => {{
65
+ window._webDeviceId = device_id;
66
+ console.log('device_id:', device_id);
67
+ }});
68
+ player.connect();
69
+ }};
70
+ </script>
71
+ """
 
 
 
 
 
72
 
73
  return (
74
  gr.update(visible=True, value="βœ… Logged in! Select a playlist below."),
 
83
  owner= data["owner"]["display_name"]
84
  desc = data.get("description","")
85
  html = f"""
86
+ <img src="{img}" width="300"/><br/>
87
  <strong>{playlist_name}</strong> by {owner}<br/>{desc}
88
  """
89
  return html, gr.update(visible=True)
90
 
91
  def shuffle_and_play(playlist_name: str):
92
  pid = user_playlists[playlist_name]
 
93
  tracks, res = [], sp.playlist_tracks(pid)
94
  tracks.extend(res["items"])
95
  while res["next"]:
96
  res = sp.next(res)
97
  tracks.extend(res["items"])
98
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
99
+ random.shuffle(uris)
100
 
101
  uris_json = json.dumps(uris)
102
  play_js = f"""
103
+ <script>
104
+ fetch('https://api.spotify.com/v1/me/player/play?device_id=' + window._webDeviceId, {{
105
+ method: 'PUT',
106
+ headers: {{
107
+ 'Authorization': 'Bearer ' + window.ACCESS_TOKEN,
108
+ 'Content-Type': 'application/json'
109
+ }},
110
+ body: JSON.stringify({{ uris: {uris_json} }})
111
+ }});
112
+ </script>
113
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  return gr.update(value="▢️ Now playing in-browser!" + play_js, visible=True)
115
 
116
  with gr.Blocks() as demo:
 
117
  gr.HTML("""
118
+ <script>
119
+ if (window.self !== window.top) {
120
+ window.top.location.href = window.location.href;
121
+ }
122
+ </script>
123
+ """)
124
+ gr.HTML('<a href="https://jisaacso219-rng-shuffle.hf.space/" target="_blank">Open standalone</a>')
125
+
126
+ gr.Markdown("Login β†’ Select playlist β†’ Shuffle & Play")
127
+
 
 
 
128
  login_btn = gr.Button("πŸ” Step 1: Login to Spotify")
129
  login_btn.click(
130
  fn=None, inputs=None, outputs=None,
131
  js=f"() => window.location.href = '{get_auth_url()}'"
132
  )
133
 
134
+ code_state = gr.Textbox(visible=False) # βœ… Critical Fix
135
+ status = gr.Markdown(visible=False)
136
+ playlist_dd = gr.Dropdown([], label="Select a Playlist", visible=False)
137
+ sdk_html = gr.HTML(visible=False)
 
138
 
139
+ info_html = gr.HTML(visible=False)
140
+ shuffle_btn = gr.Button("Shuffle & Play", visible=False)
141
+ result = gr.HTML(visible=False)
142
 
 
143
  demo.load(
144
  fn=check_login,
145
  inputs=[code_state],
 
152
 
153
  if __name__ == "__main__":
154
  demo.launch(server_name="0.0.0.0", ssr_mode=False)
155
+