jisaacso219 commited on
Commit
7507bae
Β·
verified Β·
1 Parent(s): 9cf08d5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -22
app.py CHANGED
@@ -6,13 +6,17 @@ from spotipy.oauth2 import SpotifyOAuth
6
  import random
7
 
8
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
 
9
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
 
 
10
  SCOPE = (
11
  "streaming "
12
  "user-read-playback-state "
13
  "user-modify-playback-state "
14
  "playlist-read-private"
15
  )
 
16
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
17
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
18
 
@@ -23,6 +27,7 @@ sp_oauth = SpotifyOAuth(
23
  scope=SCOPE,
24
  show_dialog=True,
25
  )
 
26
  sp = None
27
  user_playlists = {}
28
 
@@ -34,21 +39,26 @@ def get_auth_url():
34
  def check_login(code: str):
35
  print("[SERVER] check_login code:", code)
36
  global sp, user_playlists
 
37
  if not code:
 
38
  return (
39
- gr.update(visible=False),
40
- gr.update(visible=False),
41
- gr.update(visible=False),
42
  )
 
 
43
  tokinfo = sp_oauth.get_access_token(code, as_dict=True)
44
  access_token = tokinfo["access_token"]
45
  print("[SERVER] Received token:", access_token[:8], "…")
 
46
  sp = spotipy.Spotify(auth=access_token)
47
  items = sp.current_user_playlists(limit=50)["items"]
48
  user_playlists = {p["name"]: p["id"] for p in items}
49
  print("[SERVER] Playlists:", list(user_playlists.keys()))
50
 
51
- # inject token + SDK loader + init + debug listeners
52
  sdk_js = f"""
53
  <script>
54
  console.log("[SDK] Setting ACCESS_TOKEN");
@@ -63,19 +73,21 @@ def check_login(code: str):
63
  getOAuthToken: cb => cb(window.ACCESS_TOKEN),
64
  volume: 0.5
65
  }});
 
66
  // log errors
67
  ['initialization_error','authentication_error','account_error','playback_error']
68
  .forEach(evt => player.addListener(evt, e => console.error('[SDK ' + evt + ']', e)));
69
- player.addListener('ready', {{ device_id }} => {{
 
70
  console.log('[SDK] Player ready, device_id:', device_id);
71
  window._webDeviceId = device_id;
72
  }});
73
  player.addListener('player_state_changed', state => console.log('[SDK] state_changed', state));
74
- player.connect().then(s => console.log('[SDK] connect()', s));
 
75
  }};
76
  </script>
77
  """
78
-
79
  return (
80
  gr.update(visible=True, value="βœ… Logged in! Choose a playlist below."),
81
  gr.update(visible=True, choices=list(user_playlists.keys())),
@@ -89,7 +101,7 @@ def load_playlist_info(pl_name: str):
89
  img = data["images"][0]["url"] if data["images"] else ""
90
  owner = data["owner"]["display_name"]
91
  desc = data.get("description", "")
92
- html = f"""
93
  <img src="{img}" width="300" style="border-radius:8px;"/><br/>
94
  <strong>{pl_name}</strong> by {owner}<br/>{desc}
95
  """
@@ -102,18 +114,19 @@ def shuffle_and_play(pl_name: str):
102
  print("[SERVER] No playlist selected")
103
  return gr.update(value="⚠️ No playlist selected.", visible=True)
104
 
105
- # collect & shuffle URIs
106
  tracks, results = [], sp.playlist_tracks(pid)
107
  tracks.extend(results["items"])
108
  while results["next"]:
109
- results = sp.next(results); tracks.extend(results["items"])
 
110
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
111
  random.shuffle(uris)
112
  print(f"[SERVER] Shuffled {len(uris)} tracks")
113
 
114
- # JS snippet with debug output in the UI
115
  uris_json = json.dumps(uris)
116
- play_js = f"""
117
  <div id="player_debug" style="color:white;font-family:monospace;"></div>
118
  <script>
119
  console.log("[JS] Starting playback, device_id:", window._webDeviceId);
@@ -145,37 +158,44 @@ def shuffle_and_play(pl_name: str):
145
  """
146
  return gr.update(value="▢️ Now playing in-browser!" + play_js, visible=True)
147
 
 
148
  with gr.Blocks() as demo:
 
 
 
 
149
  gr.Markdown("""
150
- ⚠️ **Open in its own tab** (click the πŸ”— icon top-right)
151
- after logging in, check your browser console for SDK logs.
152
  """)
153
 
 
154
  login_btn = gr.Button(
155
  "πŸ” Step 1: Login to Spotify",
156
  link=get_auth_url()
157
  )
158
 
159
- # placeholders for code, status, playlists, sdk scripts
160
  code_box = gr.Textbox(visible=False, elem_id="auth_code")
161
  status = gr.Markdown(visible=False)
162
  dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
163
- html_token = gr.HTML(visible=False) # will inject our SDK + init + debug
164
 
 
165
  info_html = gr.HTML(visible=False)
166
  shuffle_btn= gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
167
  result = gr.HTML(visible=False)
168
 
 
169
  demo.load(
170
  fn=check_login,
171
  inputs=[code_box],
172
  outputs=[status, dropdown, html_token],
173
  js="""
174
- () => {
175
- const c = new URLSearchParams(window.location.search).get('code') || "";
176
- console.log("[JS] demo.load code:", c);
177
- return c;
178
- }
179
  """
180
  )
181
 
@@ -184,4 +204,3 @@ with gr.Blocks() as demo:
184
 
185
  if __name__ == "__main__":
186
  demo.launch()
187
-
 
6
  import random
7
 
8
  # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
9
+ # 1) Redirect URI (must exactly match your Spotify Dashboard)
10
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
11
+
12
+ # 2) Include `streaming` in your scopes for Web Playback SDK
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
 
 
27
  scope=SCOPE,
28
  show_dialog=True,
29
  )
30
+
31
  sp = None
32
  user_playlists = {}
33
 
 
39
  def check_login(code: str):
40
  print("[SERVER] check_login code:", code)
41
  global sp, user_playlists
42
+
43
  if not code:
44
+ # still waiting for Spotify redirect
45
  return (
46
+ gr.update(visible=False), # status
47
+ gr.update(visible=False), # dropdown
48
+ gr.update(visible=False), # html_token
49
  )
50
+
51
+ # Exchange code for token
52
  tokinfo = sp_oauth.get_access_token(code, as_dict=True)
53
  access_token = tokinfo["access_token"]
54
  print("[SERVER] Received token:", access_token[:8], "…")
55
+
56
  sp = spotipy.Spotify(auth=access_token)
57
  items = sp.current_user_playlists(limit=50)["items"]
58
  user_playlists = {p["name"]: p["id"] for p in items}
59
  print("[SERVER] Playlists:", list(user_playlists.keys()))
60
 
61
+ # Inject token + SDK loader + init + debug listeners
62
  sdk_js = f"""
63
  <script>
64
  console.log("[SDK] Setting ACCESS_TOKEN");
 
73
  getOAuthToken: cb => cb(window.ACCESS_TOKEN),
74
  volume: 0.5
75
  }});
76
+
77
  // log errors
78
  ['initialization_error','authentication_error','account_error','playback_error']
79
  .forEach(evt => player.addListener(evt, e => console.error('[SDK ' + evt + ']', e)));
80
+
81
+ player.addListener('ready', ({{ device_id }}) => {{
82
  console.log('[SDK] Player ready, device_id:', device_id);
83
  window._webDeviceId = device_id;
84
  }});
85
  player.addListener('player_state_changed', state => console.log('[SDK] state_changed', state));
86
+
87
+ player.connect().then(success => console.log('[SDK] connect()', success));
88
  }};
89
  </script>
90
  """
 
91
  return (
92
  gr.update(visible=True, value="βœ… Logged in! Choose a playlist below."),
93
  gr.update(visible=True, choices=list(user_playlists.keys())),
 
101
  img = data["images"][0]["url"] if data["images"] else ""
102
  owner = data["owner"]["display_name"]
103
  desc = data.get("description", "")
104
+ html = f"""
105
  <img src="{img}" width="300" style="border-radius:8px;"/><br/>
106
  <strong>{pl_name}</strong> by {owner}<br/>{desc}
107
  """
 
114
  print("[SERVER] No playlist selected")
115
  return gr.update(value="⚠️ No playlist selected.", visible=True)
116
 
117
+ # Gather & shuffle URIs
118
  tracks, results = [], sp.playlist_tracks(pid)
119
  tracks.extend(results["items"])
120
  while results["next"]:
121
+ results = sp.next(results)
122
+ tracks.extend(results["items"])
123
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
124
  random.shuffle(uris)
125
  print(f"[SERVER] Shuffled {len(uris)} tracks")
126
 
127
+ # JS snippet with on‐UI debugging
128
  uris_json = json.dumps(uris)
129
+ play_js = f"""
130
  <div id="player_debug" style="color:white;font-family:monospace;"></div>
131
  <script>
132
  console.log("[JS] Starting playback, device_id:", window._webDeviceId);
 
158
  """
159
  return gr.update(value="▢️ Now playing in-browser!" + play_js, visible=True)
160
 
161
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
162
  with gr.Blocks() as demo:
163
+ # --- Force users to pop out of the iframe ---
164
+ gr.Markdown("[πŸ”— Open this app in a standalone tab](https://jisaacso219-rng-shuffle.hf.space/)")
165
+ gr.Button("πŸ”— Open in New Tab", link="https://jisaacso219-rng-shuffle.hf.space/")
166
+
167
  gr.Markdown("""
168
+ ⚠️ After opening in a new tab, click **Step 1: Login to Spotify**,
169
+ then check your browser console for SDK logs.
170
  """)
171
 
172
+ # Step 1: OAuth
173
  login_btn = gr.Button(
174
  "πŸ” Step 1: Login to Spotify",
175
  link=get_auth_url()
176
  )
177
 
 
178
  code_box = gr.Textbox(visible=False, elem_id="auth_code")
179
  status = gr.Markdown(visible=False)
180
  dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
181
+ html_token = gr.HTML(visible=False) # Web Playback SDK injector
182
 
183
+ # Step 2 & 3: Playlist info + Shuffle & Play
184
  info_html = gr.HTML(visible=False)
185
  shuffle_btn= gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
186
  result = gr.HTML(visible=False)
187
 
188
+ # On each load: grab `?code=` and call check_login
189
  demo.load(
190
  fn=check_login,
191
  inputs=[code_box],
192
  outputs=[status, dropdown, html_token],
193
  js="""
194
+ () => {
195
+ const c = new URLSearchParams(window.location.search).get('code') || "";
196
+ console.log("[JS] demo.load code:", c);
197
+ return c;
198
+ }
199
  """
200
  )
201
 
 
204
 
205
  if __name__ == "__main__":
206
  demo.launch()