Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,11 +1,12 @@
|
|
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 |
REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
|
10 |
SCOPE = (
|
11 |
"streaming "
|
@@ -35,26 +36,31 @@ def get_auth_url():
|
|
35 |
def check_login(code: str):
|
36 |
print("[SERVER] check_login code:", code)
|
37 |
global sp, user_playlists
|
|
|
38 |
if not code:
|
|
|
39 |
return (
|
40 |
-
gr.update(visible=False),
|
41 |
-
gr.update(visible=False),
|
42 |
-
gr.update(visible=False),
|
43 |
)
|
|
|
|
|
44 |
tokinfo = sp_oauth.get_access_token(code, as_dict=True)
|
45 |
access_token = tokinfo["access_token"]
|
46 |
print("[SERVER] Received token:", access_token[:8], "β¦")
|
47 |
sp = spotipy.Spotify(auth=access_token)
|
48 |
|
|
|
49 |
items = sp.current_user_playlists(limit=50)["items"]
|
50 |
user_playlists = {p["name"]: p["id"] for p in items}
|
51 |
print("[SERVER] Playlists:", list(user_playlists.keys()))
|
52 |
|
|
|
53 |
sdk_js = f"""
|
54 |
<script>
|
55 |
-
// Break out of any iframe after login
|
56 |
if (window.self !== window.top) {{
|
57 |
-
console.log("β οΈ
|
58 |
window.top.location.href = window.location.href;
|
59 |
}}
|
60 |
console.log("[SDK] Setting ACCESS_TOKEN");
|
@@ -76,7 +82,7 @@ def check_login(code: str):
|
|
76 |
window._webDeviceId = device_id;
|
77 |
}});
|
78 |
player.addListener('player_state_changed', state => console.log('[SDK] state_changed', state));
|
79 |
-
player.connect().then(
|
80 |
}};
|
81 |
</script>
|
82 |
"""
|
@@ -107,6 +113,7 @@ def shuffle_and_play(pl_name: str):
|
|
107 |
print("[SERVER] No playlist selected")
|
108 |
return gr.update(value="β οΈ No playlist selected.", visible=True)
|
109 |
|
|
|
110 |
tracks, results = [], sp.playlist_tracks(pid)
|
111 |
tracks.extend(results["items"])
|
112 |
while results["next"]:
|
@@ -117,7 +124,7 @@ def shuffle_and_play(pl_name: str):
|
|
117 |
print(f"[SERVER] Shuffled {len(uris)} tracks")
|
118 |
|
119 |
uris_json = json.dumps(uris)
|
120 |
-
play_js
|
121 |
<div id="player_debug" style="color:white;font-family:monospace;"></div>
|
122 |
<script>
|
123 |
console.log("[JS] Starting playback, device_id:", window._webDeviceId);
|
@@ -132,13 +139,13 @@ def shuffle_and_play(pl_name: str):
|
|
132 |
'Authorization': 'Bearer ' + window.ACCESS_TOKEN,
|
133 |
'Content-Type': 'application/json'
|
134 |
}},
|
135 |
-
body: JSON.stringify({{uris:
|
136 |
}}
|
137 |
);
|
138 |
const text = await resp.text();
|
139 |
console.log("[JS] fetch status:", resp.status, text);
|
140 |
document.getElementById("player_debug").innerText =
|
141 |
-
`[JS] fetch status: ${resp.status} β ${text}`;
|
142 |
}} catch(e) {{
|
143 |
console.error("[JS] Playback error:", e);
|
144 |
document.getElementById("player_debug").innerText =
|
@@ -149,31 +156,28 @@ def shuffle_and_play(pl_name: str):
|
|
149 |
"""
|
150 |
return gr.update(value="βΆοΈ Now playing in-browser!" + play_js, visible=True)
|
151 |
|
152 |
-
# ββββββββββββββββββββββββββββββββββββββββββββββ
|
153 |
with gr.Blocks() as demo:
|
154 |
-
#
|
155 |
gr.HTML("""
|
156 |
<script>
|
157 |
if (window.self !== window.top) {
|
158 |
-
console.log("β οΈ
|
159 |
window.top.location.href = window.location.href;
|
160 |
}
|
161 |
</script>
|
162 |
""")
|
163 |
-
|
164 |
-
# 2) Fallback link with target="_blank"
|
165 |
gr.HTML(
|
166 |
-
'<a href="https://jisaacso219-rng-shuffle.hf.space/"
|
167 |
-
'style="font-size:16px;">π Open
|
168 |
)
|
|
|
169 |
|
170 |
-
#
|
171 |
-
gr.
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
"π Step 1: Login to Spotify",
|
176 |
-
link=get_auth_url()
|
177 |
)
|
178 |
|
179 |
code_box = gr.Textbox(visible=False, elem_id="auth_code")
|
@@ -181,22 +185,20 @@ with gr.Blocks() as demo:
|
|
181 |
dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
|
182 |
html_token = gr.HTML(visible=False)
|
183 |
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
result = gr.HTML(visible=False)
|
188 |
|
189 |
-
# 6) demo.load for OAuth callback
|
190 |
demo.load(
|
191 |
fn=check_login,
|
192 |
inputs=[code_box],
|
193 |
outputs=[status, dropdown, html_token],
|
194 |
js="""
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
"""
|
201 |
)
|
202 |
|
|
|
1 |
import os
|
2 |
import json
|
3 |
+
import random
|
4 |
import gradio as gr
|
5 |
import spotipy
|
6 |
from spotipy.oauth2 import SpotifyOAuth
|
|
|
7 |
|
8 |
# ββββββββββββββββββββββββββββββββββββββββββββββ
|
9 |
+
# Configuration
|
10 |
REDIRECT_URI = "https://jisaacso219-rng-shuffle.hf.space/"
|
11 |
SCOPE = (
|
12 |
"streaming "
|
|
|
36 |
def check_login(code: str):
|
37 |
print("[SERVER] check_login code:", code)
|
38 |
global sp, user_playlists
|
39 |
+
|
40 |
if not code:
|
41 |
+
# still waiting for OAuth redirect
|
42 |
return (
|
43 |
+
gr.update(visible=False), # status
|
44 |
+
gr.update(visible=False), # dropdown
|
45 |
+
gr.update(visible=False), # html_token
|
46 |
)
|
47 |
+
|
48 |
+
# Exchange code for token
|
49 |
tokinfo = sp_oauth.get_access_token(code, as_dict=True)
|
50 |
access_token = tokinfo["access_token"]
|
51 |
print("[SERVER] Received token:", access_token[:8], "β¦")
|
52 |
sp = spotipy.Spotify(auth=access_token)
|
53 |
|
54 |
+
# Fetch playlists
|
55 |
items = sp.current_user_playlists(limit=50)["items"]
|
56 |
user_playlists = {p["name"]: p["id"] for p in items}
|
57 |
print("[SERVER] Playlists:", list(user_playlists.keys()))
|
58 |
|
59 |
+
# Inject SDK + debug scripts + iframe escape
|
60 |
sdk_js = f"""
|
61 |
<script>
|
|
|
62 |
if (window.self !== window.top) {{
|
63 |
+
console.log("β οΈ Busting out of iframeβ¦");
|
64 |
window.top.location.href = window.location.href;
|
65 |
}}
|
66 |
console.log("[SDK] Setting ACCESS_TOKEN");
|
|
|
82 |
window._webDeviceId = device_id;
|
83 |
}});
|
84 |
player.addListener('player_state_changed', state => console.log('[SDK] state_changed', state));
|
85 |
+
player.connect().then(success => console.log('[SDK] connect()', success));
|
86 |
}};
|
87 |
</script>
|
88 |
"""
|
|
|
113 |
print("[SERVER] No playlist selected")
|
114 |
return gr.update(value="β οΈ No playlist selected.", visible=True)
|
115 |
|
116 |
+
# Gather & shuffle URIs
|
117 |
tracks, results = [], sp.playlist_tracks(pid)
|
118 |
tracks.extend(results["items"])
|
119 |
while results["next"]:
|
|
|
124 |
print(f"[SERVER] Shuffled {len(uris)} tracks")
|
125 |
|
126 |
uris_json = json.dumps(uris)
|
127 |
+
play_js = f"""
|
128 |
<div id="player_debug" style="color:white;font-family:monospace;"></div>
|
129 |
<script>
|
130 |
console.log("[JS] Starting playback, device_id:", window._webDeviceId);
|
|
|
139 |
'Authorization': 'Bearer ' + window.ACCESS_TOKEN,
|
140 |
'Content-Type': 'application/json'
|
141 |
}},
|
142 |
+
body: JSON.stringify({{uris:{uris_json}}})
|
143 |
}}
|
144 |
);
|
145 |
const text = await resp.text();
|
146 |
console.log("[JS] fetch status:", resp.status, text);
|
147 |
document.getElementById("player_debug").innerText =
|
148 |
+
`[JS] fetch status: ${{resp.status}} β ${{text}}`;
|
149 |
}} catch(e) {{
|
150 |
console.error("[JS] Playback error:", e);
|
151 |
document.getElementById("player_debug").innerText =
|
|
|
156 |
"""
|
157 |
return gr.update(value="βΆοΈ Now playing in-browser!" + play_js, visible=True)
|
158 |
|
|
|
159 |
with gr.Blocks() as demo:
|
160 |
+
# Auto-bust iframe on load
|
161 |
gr.HTML("""
|
162 |
<script>
|
163 |
if (window.self !== window.top) {
|
164 |
+
console.log("β οΈ Busting out of iframe on load");
|
165 |
window.top.location.href = window.location.href;
|
166 |
}
|
167 |
</script>
|
168 |
""")
|
169 |
+
# Fallback link
|
|
|
170 |
gr.HTML(
|
171 |
+
'<a href="https://jisaacso219-rng-shuffle.hf.space/" '
|
172 |
+
'target="_blank" style="font-size:16px;">π Open standalone</a>'
|
173 |
)
|
174 |
+
gr.Markdown("After opening standalone, click **Step 1: Login to Spotify**β¦")
|
175 |
|
176 |
+
# OAuth button (same tab)
|
177 |
+
login_btn = gr.Button("π Step 1: Login to Spotify")
|
178 |
+
login_btn.click(
|
179 |
+
fn=None, inputs=None, outputs=None,
|
180 |
+
js=f"() => window.location.href = '{get_auth_url()}'"
|
|
|
|
|
181 |
)
|
182 |
|
183 |
code_box = gr.Textbox(visible=False, elem_id="auth_code")
|
|
|
185 |
dropdown = gr.Dropdown(choices=[], label="Step 2: Select a Playlist", visible=False)
|
186 |
html_token = gr.HTML(visible=False)
|
187 |
|
188 |
+
info_html = gr.HTML(visible=False)
|
189 |
+
shuffle_btn= gr.Button("π Step 3: Shuffle & Play", visible=False)
|
190 |
+
result = gr.HTML(visible=False)
|
|
|
191 |
|
|
|
192 |
demo.load(
|
193 |
fn=check_login,
|
194 |
inputs=[code_box],
|
195 |
outputs=[status, dropdown, html_token],
|
196 |
js="""
|
197 |
+
() => {
|
198 |
+
const c = new URLSearchParams(window.location.search).get('code') || "";
|
199 |
+
console.log("[JS] demo.load code:", c);
|
200 |
+
return c;
|
201 |
+
}
|
202 |
"""
|
203 |
)
|
204 |
|