tecuts commited on
Commit
e659c3f
·
verified ·
1 Parent(s): 8f31aed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -28
app.py CHANGED
@@ -338,38 +338,95 @@ import httpx
338
  SOUNDCLOUD_CLIENT_ID = "khI8ciOiYPX6UVGInQY5zA0zvTkfzuuC" # sniff from browser network tab on soundcloud.com
339
 
340
  @app.get("/api/list")
341
- async def get_playlist_info(request: Request, url: str, start: int = 1, end: int = 50):
342
 
343
- # 1. Resolve the URL to get playlist ID
344
- resolve = await httpx.AsyncClient().get(
345
- "https://api-v2.soundcloud.com/resolve",
346
- params={"url": url, "client_id": SOUNDCLOUD_CLIENT_ID}
347
- )
348
- data = resolve.json()
349
- playlist_id = data["id"]
350
-
351
- # 2. Fetch tracks directly
352
- offset = start - 1
353
  limit = min(end - start + 1, 50)
 
354
 
355
- tracks_res = await httpx.AsyncClient().get(
356
- f"https://api-v2.soundcloud.com/playlists/{playlist_id}/tracks",
357
- params={"client_id": SOUNDCLOUD_CLIENT_ID, "limit": limit, "offset": offset}
358
- )
359
- tracks = tracks_res.json()
360
-
361
- entries = [
362
- {
363
- "id": t.get("id"),
364
- "title": t.get("title"),
365
- "url": t.get("permalink_url"),
366
- "duration": t.get("duration"),
367
- "uploader": t.get("user", {}).get("username"),
368
- }
369
- for t in tracks
370
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
 
372
- return JSONResponse({"entries": entries, "items_returned": len(entries)})
 
 
 
 
 
 
 
373
 
374
 
375
  @app.get("/api/rate-limit-status")
 
338
  SOUNDCLOUD_CLIENT_ID = "khI8ciOiYPX6UVGInQY5zA0zvTkfzuuC" # sniff from browser network tab on soundcloud.com
339
 
340
  @app.get("/api/list")
341
+ async def get_sound_playlist_info(request: Request, url: str, start: int = 1, end: int = 50):
342
 
 
 
 
 
 
 
 
 
 
 
343
  limit = min(end - start + 1, 50)
344
+ offset = start - 1
345
 
346
+ async with httpx.AsyncClient(timeout=15) as client:
347
+
348
+ # 1. Resolve URL
349
+ resolve_res = await client.get(
350
+ "https://api-v2.soundcloud.com/resolve",
351
+ params={"url": url, "client_id": SOUNDCLOUD_CLIENT_ID}
352
+ )
353
+ if resolve_res.status_code != 200:
354
+ raise HTTPException(status_code=404, detail=f"Could not resolve URL: {resolve_res.text}")
355
+
356
+ data = resolve_res.json()
357
+
358
+ # 2. Handle both playlists and user profiles
359
+ if data.get("kind") == "playlist":
360
+ playlist_id = data["id"]
361
+
362
+ # Playlists return a `tracks` array but lazy tracks only have `id`
363
+ # Collect IDs from the paginated slice first
364
+ all_track_ids = [t["id"] for t in data.get("tracks", [])]
365
+ paginated_ids = all_track_ids[offset: offset + limit]
366
+
367
+ if not paginated_ids:
368
+ return JSONResponse({"entries": [], "items_returned": 0})
369
+
370
+ # 3. Fetch full track details in one batch request
371
+ tracks_res = await client.get(
372
+ "https://api-v2.soundcloud.com/tracks",
373
+ params={
374
+ "ids": ",".join(str(i) for i in paginated_ids),
375
+ "client_id": SOUNDCLOUD_CLIENT_ID
376
+ }
377
+ )
378
+ if tracks_res.status_code != 200:
379
+ raise HTTPException(status_code=502, detail=f"Track fetch failed: {tracks_res.text}")
380
+
381
+ tracks = tracks_res.json()
382
+
383
+ elif data.get("kind") == "user":
384
+ # For user profiles, fetch their tracks directly
385
+ tracks_res = await client.get(
386
+ f"https://api-v2.soundcloud.com/users/{data['id']}/tracks",
387
+ params={
388
+ "client_id": SOUNDCLOUD_CLIENT_ID,
389
+ "limit": limit,
390
+ "offset": offset
391
+ }
392
+ )
393
+ if tracks_res.status_code != 200:
394
+ raise HTTPException(status_code=502, detail=f"Track fetch failed: {tracks_res.text}")
395
+
396
+ tracks = tracks_res.json().get("collection", [])
397
+
398
+ else:
399
+ raise HTTPException(status_code=400, detail=f"Unsupported kind: {data.get('kind')}")
400
+
401
+ entries = [
402
+ {
403
+ "id": t.get("id"),
404
+ "title": t.get("title"),
405
+ "url": t.get("permalink_url"),
406
+ "duration": t.get("duration"),
407
+ "uploader": t.get("user", {}).get("username"),
408
+ }
409
+ for t in tracks
410
+ ]
411
+
412
+ # Next page
413
+ next_page_url = None
414
+ total = data.get("track_count") or data.get("likes_count")
415
+ if total and (offset + limit) < total:
416
+ next_start = end + 1
417
+ next_end = next_start + 49
418
+ encoded_url = urllib.parse.quote(url)
419
+ base_url = str(request.base_url).rstrip('/')
420
+ next_page_url = f"{base_url}/api/playlist?url={encoded_url}&start={next_start}&end={next_end}"
421
 
422
+ return JSONResponse({
423
+ "id": data.get("id"),
424
+ "title": data.get("title") or data.get("username"),
425
+ "uploader": data.get("username") or data.get("uploader"),
426
+ "items_returned": len(entries),
427
+ "next_page": next_page_url,
428
+ "entries": entries
429
+ })
430
 
431
 
432
  @app.get("/api/rate-limit-status")