Chrunos commited on
Commit
98b69a3
·
verified ·
1 Parent(s): c94a9fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -0
app.py CHANGED
@@ -301,6 +301,103 @@ async def get_playlist_info(
301
  headers={"Cache-Control": "no-store, max-age=0"},
302
  )
303
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  @app.get("/api/rate-limit-status")
305
  async def get_rate_limit_status(request: Request):
306
  client_ip = get_client_ip(request)
 
301
  headers={"Cache-Control": "no-store, max-age=0"},
302
  )
303
 
304
+
305
+ import httpx
306
+
307
+ SOUNDCLOUD_CLIENT_ID = "khI8ciOiYPX6UVGInQY5zA0zvTkfzuuC" # sniff from browser network tab on soundcloud.com
308
+
309
+ @app.get("/api/list")
310
+ async def get_sound_playlist_info(request: Request, url: str, start: int = 1, end: int = 15):
311
+
312
+ limit = min(end - start + 1, 15)
313
+ offset = start - 1
314
+
315
+ async with httpx.AsyncClient(timeout=15) as client:
316
+
317
+ # 1. Resolve URL
318
+ resolve_res = await client.get(
319
+ "https://api-v2.soundcloud.com/resolve",
320
+ params={"url": url, "client_id": SOUNDCLOUD_CLIENT_ID}
321
+ )
322
+ if resolve_res.status_code != 200:
323
+ raise HTTPException(status_code=404, detail=f"Could not resolve URL: {resolve_res.text}")
324
+
325
+ data = resolve_res.json()
326
+
327
+ # 2. Handle both playlists and user profiles
328
+ if data.get("kind") == "playlist":
329
+ playlist_id = data["id"]
330
+
331
+ # Playlists return a `tracks` array but lazy tracks only have `id`
332
+ # Collect IDs from the paginated slice first
333
+ all_track_ids = [t["id"] for t in data.get("tracks", [])]
334
+ paginated_ids = all_track_ids[offset: offset + limit]
335
+
336
+ if not paginated_ids:
337
+ return JSONResponse({"entries": [], "items_returned": 0})
338
+
339
+ # 3. Fetch full track details in one batch request
340
+ tracks_res = await client.get(
341
+ "https://api-v2.soundcloud.com/tracks",
342
+ params={
343
+ "ids": ",".join(str(i) for i in paginated_ids),
344
+ "client_id": SOUNDCLOUD_CLIENT_ID
345
+ }
346
+ )
347
+ if tracks_res.status_code != 200:
348
+ raise HTTPException(status_code=502, detail=f"Track fetch failed: {tracks_res.text}")
349
+
350
+ tracks = tracks_res.json()
351
+
352
+ elif data.get("kind") == "user":
353
+ # For user profiles, fetch their tracks directly
354
+ tracks_res = await client.get(
355
+ f"https://api-v2.soundcloud.com/users/{data['id']}/tracks",
356
+ params={
357
+ "client_id": SOUNDCLOUD_CLIENT_ID,
358
+ "limit": limit,
359
+ "offset": offset
360
+ }
361
+ )
362
+ if tracks_res.status_code != 200:
363
+ raise HTTPException(status_code=502, detail=f"Track fetch failed: {tracks_res.text}")
364
+
365
+ tracks = tracks_res.json().get("collection", [])
366
+
367
+ else:
368
+ raise HTTPException(status_code=400, detail=f"Unsupported kind: {data.get('kind')}")
369
+
370
+ entries = [
371
+ {
372
+ "id": t.get("id"),
373
+ "title": t.get("title"),
374
+ "url": t.get("permalink_url"),
375
+ "duration": t.get("duration"),
376
+ "uploader": t.get("user", {}).get("username"),
377
+ }
378
+ for t in tracks
379
+ ]
380
+
381
+ # Next page
382
+ next_page_url = None
383
+ total = data.get("track_count") or data.get("likes_count")
384
+ if total and (offset + limit) < total:
385
+ next_start = end + 1
386
+ next_end = next_start + 14
387
+ encoded_url = urllib.parse.quote(url)
388
+ base_url = str(request.base_url).rstrip('/')
389
+ next_page_url = f"{base_url}/api/list?url={encoded_url}&start={next_start}&end={next_end}"
390
+
391
+ return JSONResponse({
392
+ "id": data.get("id"),
393
+ "title": data.get("title") or data.get("username"),
394
+ "uploader": data.get("username") or data.get("uploader"),
395
+ "items_returned": len(entries),
396
+ "next_page": next_page_url,
397
+ "entries": entries
398
+ })
399
+
400
+
401
  @app.get("/api/rate-limit-status")
402
  async def get_rate_limit_status(request: Request):
403
  client_ip = get_client_ip(request)