jisaacso219 commited on
Commit
866595f
Β·
verified Β·
1 Parent(s): a8c78b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -53
app.py CHANGED
@@ -3,6 +3,7 @@ import gradio as gr
3
  import spotipy
4
  from spotipy.oauth2 import SpotifyOAuth
5
 
 
6
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
7
  SCOPE = (
8
  "streaming "
@@ -27,94 +28,115 @@ user_playlists = {}
27
  def get_auth_url():
28
  return sp_oauth.get_authorize_url()
29
 
30
- def check_login(code):
31
  global sp, user_playlists
32
  if not code:
33
- return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)
 
 
34
  tokinfo = sp_oauth.get_access_token(code, as_dict=True)
35
  access_token = tokinfo["access_token"]
36
- sp = spotipy.Spotify(auth=access_token)
37
- items = sp.current_user_playlists(limit=50)["items"]
38
- user_playlists = {p["name"]: p["id"] for p in items}
39
- # inject token + SDK
 
40
  sdk_js = f"""
41
- <script>window.ACCESS_TOKEN="{access_token}";</script>
 
 
 
 
 
42
  <script src="https://sdk.scdn.co/spotify-player.js"></script>
43
  <script>
44
  window.onSpotifyWebPlaybackSDKReady = () => {{
 
45
  const player = new Spotify.Player({{
46
  name: 'RNG Web Player',
47
  getOAuthToken: cb => cb(window.ACCESS_TOKEN),
48
  volume: 0.5
49
  }});
50
- player.addListener('ready', ({{ device_id }}) => {{ window._webDeviceId = device_id; }});
 
 
 
51
  player.connect();
52
  }};
53
  </script>
54
  """
 
55
  return (
56
- gr.update(visible=True, value="βœ… Logged in! Pick a playlist."),
57
- gr.update(visible=True, choices=list(user_playlists.keys())),
58
- gr.update(visible=True, value=sdk_js),
59
  )
60
 
61
  def load_playlist_info(name):
62
- pid = user_playlists[name]
63
  data = sp.playlist(pid)
64
- img = data["images"][0]["url"] if data["images"] else ""
65
- owner = data["owner"]["display_name"]
66
  desc = data.get("description","")
67
- return (
68
- f"<img src='{img}' width='300'/><br/><strong>{name}</strong> by {owner}<br/>{desc}",
69
- gr.update(visible=True),
70
  )
 
71
 
72
  def shuffle_and_play(name):
73
- pid = user_playlists[name]
74
  tracks, res = [], sp.playlist_tracks(pid)
75
- tracks += res["items"]
76
  while res["next"]:
77
- res = sp.next(res)
78
- tracks += res["items"]
79
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
80
  random.shuffle(uris)
81
- uris_json = json.dumps(uris)
82
- return gr.update(
83
- value=(
84
- "▢️ Now playing in-browser!"
85
- f"<script>(async()=>{{"
86
- f"await fetch('https://api.spotify.com/v1/me/player/play?device_id='+window._webDeviceId,{{"
87
- f"method:'PUT',headers:{{'Authorization':'Bearer '+window.ACCESS_TOKEN}},"
88
- f"body:JSON.stringify({{'uris':{uris_json}}})}});"
89
- f"}})();</script>"
90
- ),
91
- visible=True
92
- )
 
 
 
 
 
 
 
 
 
 
93
 
94
  with gr.Blocks() as demo:
95
- gr.Markdown("[πŸ”— Open standalone](https://jisaacso219-rng-shuffle.hf.space/)")
96
- gr.Markdown("1) Click **Login** 2) Pick a playlist 3) Shuffle & play in-browser")
97
- login = gr.Button("πŸ” Step 1: Login", link=get_auth_url())
98
- code_box = gr.Textbox(visible=False, elem_id="auth_code")
99
- status, playlist_dd, sdk_html = [
100
- gr.Markdown(visible=False),
101
- gr.Dropdown([], label="Select Playlist", visible=False),
102
- gr.HTML(visible=False)
103
- ]
104
- info_html = gr.HTML(visible=False)
105
- shuffle_btn = gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
106
- result = gr.HTML(visible=False)
107
 
108
  demo.load(
109
- fn=check_login,
110
- inputs=[code_box],
111
- outputs=[status, playlist_dd, sdk_html],
112
- js="() => new URLSearchParams(window.location.search).get('code') || ''"
113
  )
114
-
115
- playlist_dd.change(load_playlist_info, [playlist_dd], [info_html, shuffle_btn])
116
- shuffle_btn.click(shuffle_and_play, [playlist_dd], [result])
117
 
118
  if __name__ == "__main__":
119
  demo.launch(ssr_mode=False)
120
-
 
3
  import spotipy
4
  from spotipy.oauth2 import SpotifyOAuth
5
 
6
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
7
  REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
8
  SCOPE = (
9
  "streaming "
 
28
  def get_auth_url():
29
  return sp_oauth.get_authorize_url()
30
 
31
+ def check_login(code: str):
32
  global sp, user_playlists
33
  if not code:
34
+ return (gr.update(visible=False),
35
+ gr.update(visible=False),
36
+ gr.update(visible=False))
37
  tokinfo = sp_oauth.get_access_token(code, as_dict=True)
38
  access_token = tokinfo["access_token"]
39
+ sp = spotipy.Spotify(auth=access_token)
40
+ items = sp.current_user_playlists(limit=50)["items"]
41
+ user_playlists= {p["name"]: p["id"] for p in items}
42
+
43
+ # Inject the Web Playback SDK + escape any iframe
44
  sdk_js = f"""
45
+ <script>
46
+ if (window.self !== window.top) {{
47
+ window.top.location.href = window.location.href;
48
+ }}
49
+ window.ACCESS_TOKEN = "{access_token}";
50
+ </script>
51
  <script src="https://sdk.scdn.co/spotify-player.js"></script>
52
  <script>
53
  window.onSpotifyWebPlaybackSDKReady = () => {{
54
+ console.log("[SDK] Ready");
55
  const player = new Spotify.Player({{
56
  name: 'RNG Web Player',
57
  getOAuthToken: cb => cb(window.ACCESS_TOKEN),
58
  volume: 0.5
59
  }});
60
+ player.addListener('ready', ({ device_id }) => {{
61
+ console.log('[SDK] device_id:', device_id);
62
+ window._webDeviceId = device_id;
63
+ }});
64
  player.connect();
65
  }};
66
  </script>
67
  """
68
+
69
  return (
70
+ gr.update(visible=True, value="βœ… Logged in! Pick a playlist."),
71
+ gr.update(visible=True, choices=list(user_playlists.keys())),
72
+ gr.update(visible=True, value=sdk_js)
73
  )
74
 
75
  def load_playlist_info(name):
76
+ pid = user_playlists[name]
77
  data = sp.playlist(pid)
78
+ img = data["images"][0]["url"] if data["images"] else ""
79
+ owner= data["owner"]["display_name"]
80
  desc = data.get("description","")
81
+ html = (
82
+ f"<img src='{img}' width='300'/><br/>"
83
+ f"<strong>{name}</strong> by {owner}<br/>{desc}"
84
  )
85
+ return html, gr.update(visible=True)
86
 
87
  def shuffle_and_play(name):
88
+ pid = user_playlists[name]
89
  tracks, res = [], sp.playlist_tracks(pid)
90
+ tracks.extend(res["items"])
91
  while res["next"]:
92
+ res = sp.next(res); tracks.extend(res["items"])
 
93
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
94
  random.shuffle(uris)
95
+
96
+ # Kick off in-browser playback
97
+ js = json.dumps(uris)
98
+ play_js = f"""
99
+ <script>
100
+ (async () => {{
101
+ const token = window.ACCESS_TOKEN;
102
+ const device_id = window._webDeviceId;
103
+ console.log("[JS] PLAY", device_id, {len(uris)},"URIs");
104
+ const resp = await fetch(
105
+ 'https://api.spotify.com/v1/me/player/play?device_id=' + device_id,
106
+ {{
107
+ method:'PUT',
108
+ headers:{{'Authorization':'Bearer '+token,'Content-Type':'application/json'}},
109
+ body:JSON.stringify({{'uris':{js}}})
110
+ }}
111
+ );
112
+ console.log("[JS] status:", resp.status);
113
+ }})();
114
+ </script>
115
+ """
116
+ return gr.update(value="▢️ Now playing in-browser!" + play_js, visible=True)
117
 
118
  with gr.Blocks() as demo:
119
+ gr.HTML(
120
+ '<a href="https://jisaacso219-rng-shuffle.hf.space/" '
121
+ 'target="_blank">πŸ”— Open standalone</a>'
122
+ )
123
+ gr.Button("πŸ” Step 1: Login", link=get_auth_url())
124
+ code_box = gr.Textbox(visible=False, elem_id="auth_code")
125
+ status = gr.Markdown(visible=False)
126
+ dropdown = gr.Dropdown([], label="Select Playlist", visible=False)
127
+ sdk_html = gr.HTML(visible=False)
128
+ info_html = gr.HTML(visible=False)
129
+ shuffle_btn= gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
130
+ result = gr.HTML(visible=False)
131
 
132
  demo.load(
133
+ fn=check_login,
134
+ inputs=[code_box],
135
+ outputs=[status, dropdown, sdk_html],
136
+ js="() => new URLSearchParams(window.location.search).get('code')||''"
137
  )
138
+ dropdown.change(load_playlist_info, [dropdown], [info_html, shuffle_btn])
139
+ shuffle_btn.click(shuffle_and_play, [dropdown], [result])
 
140
 
141
  if __name__ == "__main__":
142
  demo.launch(ssr_mode=False)