tecuts commited on
Commit
75c4b89
·
verified ·
1 Parent(s): 8d69ef7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -2
app.py CHANGED
@@ -220,17 +220,21 @@ async def get_playlist_info(
220
  """
221
  Fetches paginated items from a playlist or user profile.
222
  Strictly enforces a maximum of 50 items per request and provides a next_page URL.
 
223
  """
 
224
  if start < 1:
225
  raise HTTPException(status_code=400, detail="'start' must be 1 or greater.")
226
  if end < start:
227
  raise HTTPException(status_code=400, detail="'end' must be greater than or equal to 'start'.")
228
 
 
229
  requested_count = end - start + 1
230
  if requested_count > 50:
231
  end = start + 49
232
  requested_count = 50
233
 
 
234
  client_ip = get_client_ip(request)
235
  is_allowed, remaining = check_rate_limit(client_ip)
236
 
@@ -254,25 +258,45 @@ async def get_playlist_info(
254
  "ignoreerrors": True,
255
  "cachedir": "/tmp/yt-dlp-cache",
256
  "js-runtimes": "node",
 
257
  "playliststart": start,
258
  "playlistend": end
259
  }
260
 
261
- with YoutubeDL(ydl_options) as ytdl:
262
  try:
263
  response = ytdl.extract_info(url, download=False)
264
  if not response:
265
  raise HTTPException(status_code=404, detail="Playlist or profile not found.")
266
 
 
267
  raw_entries = response.get("entries") or []
268
- valid_entries = [e for e in raw_entries if e is not None]
 
 
 
 
 
 
 
 
 
 
 
 
269
 
 
270
  next_page_url = None
 
271
  if len(raw_entries) >= requested_count:
272
  next_start = end + 1
273
  next_end = next_start + 49
 
 
274
  encoded_url = urllib.parse.quote(url)
275
  base_url = str(request.base_url).rstrip('/')
 
 
276
  next_page_url = f"{base_url}/api/playlist?url={encoded_url}&start={next_start}&end={next_end}"
277
 
278
  clean_response = {
@@ -300,6 +324,7 @@ async def get_playlist_info(
300
  detail=repr(e),
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):
 
220
  """
221
  Fetches paginated items from a playlist or user profile.
222
  Strictly enforces a maximum of 50 items per request and provides a next_page URL.
223
+ Includes sanitization for lazy-loaded SoundCloud tracks.
224
  """
225
+ # 1. Validate inputs
226
  if start < 1:
227
  raise HTTPException(status_code=400, detail="'start' must be 1 or greater.")
228
  if end < start:
229
  raise HTTPException(status_code=400, detail="'end' must be greater than or equal to 'start'.")
230
 
231
+ # 2. Enforce a hard limit of 50 items per request
232
  requested_count = end - start + 1
233
  if requested_count > 50:
234
  end = start + 49
235
  requested_count = 50
236
 
237
+ # Rate Limiting
238
  client_ip = get_client_ip(request)
239
  is_allowed, remaining = check_rate_limit(client_ip)
240
 
 
258
  "ignoreerrors": True,
259
  "cachedir": "/tmp/yt-dlp-cache",
260
  "js-runtimes": "node",
261
+ # Pass the strictly clamped pagination settings to yt-dlp
262
  "playliststart": start,
263
  "playlistend": end
264
  }
265
 
266
+ with YoutubeDL(ydl_options) as ydl:
267
  try:
268
  response = ytdl.extract_info(url, download=False)
269
  if not response:
270
  raise HTTPException(status_code=404, detail="Playlist or profile not found.")
271
 
272
+ # Extract entries safely
273
  raw_entries = response.get("entries") or []
274
+ valid_entries = []
275
+
276
+ # --- THE FIX: Sanitize SoundCloud URLs ---
277
+ for e in raw_entries:
278
+ if e is not None:
279
+ track_url = e.get("url", "")
280
+
281
+ # Intercept lazy-loaded API URLs and normalize them
282
+ if "api-v2.soundcloud.com/tracks/" in track_url:
283
+ track_id = track_url.split("/")[-1].split("?")[0]
284
+ e["url"] = f"https://api.soundcloud.com/tracks/{track_id}"
285
+
286
+ valid_entries.append(e)
287
 
288
+ # 3. Determine if there is a next page
289
  next_page_url = None
290
+
291
  if len(raw_entries) >= requested_count:
292
  next_start = end + 1
293
  next_end = next_start + 49
294
+
295
+ # Safely encode the target URL
296
  encoded_url = urllib.parse.quote(url)
297
  base_url = str(request.base_url).rstrip('/')
298
+
299
+ # Construct the ready-to-use next_page URL for the client
300
  next_page_url = f"{base_url}/api/playlist?url={encoded_url}&start={next_start}&end={next_end}"
301
 
302
  clean_response = {
 
324
  detail=repr(e),
325
  headers={"Cache-Control": "no-store, max-age=0"},
326
  )
327
+
328
 
329
  @app.get("/api/rate-limit-status")
330
  async def get_rate_limit_status(request: Request):