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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -101
app.py CHANGED
@@ -1,19 +1,22 @@
1
- import os, json, random
 
2
  import gradio as gr
3
  import spotipy
4
  from spotipy.oauth2 import SpotifyOAuth
5
 
6
- # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
7
- REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
8
- SCOPE = (
9
- "streaming "
10
- "user-read-playback-state "
11
- "user-modify-playback-state "
12
- "playlist-read-private"
13
- )
14
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
15
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
16
 
 
 
 
 
 
 
 
 
17
  sp_oauth = SpotifyOAuth(
18
  client_id=CLIENT_ID,
19
  client_secret=CLIENT_SECRET,
@@ -31,112 +34,86 @@ def get_auth_url():
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)
 
 
 
1
+ import os
2
+ import random
3
  import gradio as gr
4
  import spotipy
5
  from spotipy.oauth2 import SpotifyOAuth
6
 
7
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
8
+ # 1) Spotify App Credentials (in HF secrets)
 
 
 
 
 
 
9
  CLIENT_ID = os.environ["SPOTIFY_CLIENT_ID"]
10
  CLIENT_SECRET = os.environ["SPOTIFY_CLIENT_SECRET"]
11
 
12
+ # 2) Redirect URI must exactly match your Spotify Dashboard
13
+ REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
14
+
15
+ # 3) Scopes for controlling playback & reading playlists
16
+ SCOPE = "user-read-playback-state user-modify-playback-state playlist-read-private"
17
+
18
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
19
+ # Spotify OAuth helper
20
  sp_oauth = SpotifyOAuth(
21
  client_id=CLIENT_ID,
22
  client_secret=CLIENT_SECRET,
 
34
  def check_login(code: str):
35
  global sp, user_playlists
36
  if not code:
37
+ # Still waiting for Spotify to redirect back with ?code=
38
+ return (
39
+ gr.update(visible=False), # status
40
+ gr.update(visible=False), # playlist dropdown
41
+ gr.update(visible=False), # shuffle button
42
+ )
43
+
44
+ # Exchange code for an access token
45
+ token = sp_oauth.get_access_token(code)
46
+ sp = spotipy.Spotify(auth=token)
47
+
48
+ # Fetch first 50 playlists
49
+ items = sp.current_user_playlists(limit=50)["items"]
50
+ user_playlists = {p["name"]: p["id"] for p in items}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  return (
53
+ gr.update(visible=True, value="βœ… Logged in! Pick a playlist below."),
54
+ gr.update(visible=True, choices=list(user_playlists.keys())),
55
+ gr.update(visible=True),
56
  )
57
 
58
+ def shuffle_and_play(playlist_name: str):
59
+ pid = user_playlists.get(playlist_name)
60
+ if not pid:
61
+ return "⚠️ No playlist selected. Please choose one.",
62
+
63
+ # Gather all track URIs
64
+ tracks, results = [], sp.playlist_tracks(pid)
65
+ tracks.extend(results["items"])
66
+ while results["next"]:
67
+ results = sp.next(results)
68
+ tracks.extend(results["items"])
 
 
 
 
 
 
 
69
  uris = [t["track"]["uri"] for t in tracks if t["track"]]
70
+
71
+ # RNG shuffle
72
  random.shuffle(uris)
73
 
74
+ # Send to first active device
75
+ devices = sp.devices().get("devices", [])
76
+ if not devices:
77
+ return "⚠️ No active Spotify device found. Open your Spotify app and try again."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ sp.start_playback(device_id=devices[0]["id"], uris=uris)
80
+ return f"▢️ Playing shuffled **{playlist_name}** on your active device!"
81
+
82
+ # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
83
  with gr.Blocks() as demo:
84
+ gr.Markdown("## 🎡 RNG Spotify Playlist Shuffler")
85
+ gr.Markdown("1) Login β†’ 2) Pick a playlist β†’ 3) Shuffle & play")
86
+
87
+ # Step 1: Login button (same tab)
88
+ login_btn = gr.Button("πŸ” Step 1: Login to Spotify")
89
+ login_btn.click(
90
+ None, None, None,
91
+ js=f"() => window.location.href = '{get_auth_url()}'"
92
  )
 
 
 
 
 
 
 
 
93
 
94
+ # Hidden textbox to capture OAuth code
95
+ code_box = gr.Textbox(visible=False, elem_id="auth_code")
96
+ login_status = gr.Markdown(visible=False)
97
+ playlist_dd = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
98
+ shuffle_button = gr.Button("πŸ”€ Step 3: Shuffle & Play", visible=False)
99
+ result = gr.Markdown(visible=False)
100
+
101
+ # On every load (or redirect back with ?code=), call check_login
102
  demo.load(
103
  fn=check_login,
104
  inputs=[code_box],
105
+ outputs=[login_status, playlist_dd, shuffle_button],
106
+ js="() => new URLSearchParams(window.location.search).get('code') || ''"
107
+ )
108
+
109
+ # Finally: when they click Shuffle & Play
110
+ shuffle_button.click(
111
+ shuffle_and_play,
112
+ inputs=[playlist_dd],
113
+ outputs=[result]
114
  )
 
 
115
 
116
  if __name__ == "__main__":
117
+ # No SSR, default port
118
+ demo.launch(server_name="0.0.0.0", ssr_mode=False)
119
+