Poker commited on
Commit
33dda2e
·
1 Parent(s): f973023

fix: add Chrome TLS impersonation + tv_embedded client + curl-cffi for YouTube bypass

Browse files
Files changed (2) hide show
  1. app.py +14 -12
  2. requirements.txt +1 -0
app.py CHANGED
@@ -247,24 +247,25 @@ def clip_youtube_video():
247
  print(f"Downloading video from {url}...")
248
  download_cmd = [
249
  ytdlp_bin,
250
- # Quality: max 720p for reliability and speed
251
  "-f", "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio/best[height<=720]/best",
252
  "--merge-output-format", "mp4",
253
- # Use iOS player client bypasses YouTube's datacenter IP blocking
254
- # ios/android clients are not subject to the same bot detection as web
255
- "--extractor-args", "youtube:player_client=ios,android,web",
 
 
 
256
  # Geo-bypass
257
  "--geo-bypass",
258
- # SSL resilience
259
  "--no-check-certificates",
260
  "--socket-timeout", "60",
261
- # Headers to look like a real browser
262
- "--add-header", "Accept-Language:en-US,en;q=0.9",
263
  # Retry logic
264
  "--retries", "15",
265
  "--fragment-retries", "15",
266
  "--retry-sleep", "exp=2:60",
267
- "--sleep-requests", "1",
268
  # Output
269
  "-o", raw_download_path,
270
  url
@@ -272,17 +273,18 @@ def clip_youtube_video():
272
 
273
  result = subprocess.run(download_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=480)
274
  stderr_text = result.stderr.decode('utf-8', errors='ignore')
275
- stdout_text = result.stdout.decode('utf-8', errors='ignore')
276
 
277
  if result.returncode != 0 or not os.path.exists(raw_download_path) or os.path.getsize(raw_download_path) == 0:
278
  if 'SSL' in stderr_text or 'EOF' in stderr_text or 'network' in stderr_text.lower():
279
- err = 'YouTube is blocking server downloads. Please try: 1) A different video, 2) A shorter clip (<5 min), 3) An unlisted video.'
280
- elif 'Private video' in stderr_text or 'members-only' in stderr_text:
281
  err = 'This video is private or members-only. Only public videos can be downloaded.'
282
  elif 'removed' in stderr_text or 'unavailable' in stderr_text or 'not available' in stderr_text:
283
  err = 'This video is unavailable or has been removed from YouTube.'
284
  elif 'Sign in' in stderr_text or 'bot' in stderr_text.lower():
285
- err = 'YouTube requires sign-in or detected bot activity. Try a different public video.'
 
 
286
  else:
287
  err = stderr_text[-600:] if stderr_text else 'Unknown download error'
288
  return jsonify({'success': False, 'error': f'Download failed: {err}'}), 500
 
247
  print(f"Downloading video from {url}...")
248
  download_cmd = [
249
  ytdlp_bin,
250
+ # Quality: max 720p
251
  "-f", "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio/best[height<=720]/best",
252
  "--merge-output-format", "mp4",
253
+ # TLS fingerprint spoofingimpersonate a real Chrome browser at network level
254
+ # This is much more effective than just setting User-Agent headers
255
+ "--impersonate", "chrome",
256
+ # Use tv_embedded player client — bypasses datacenter IP blocking
257
+ # tv_embedded is used for embedded YouTube players and has looser restrictions
258
+ "--extractor-args", "youtube:player_client=tv_embedded,ios,android",
259
  # Geo-bypass
260
  "--geo-bypass",
261
+ # SSL resilience
262
  "--no-check-certificates",
263
  "--socket-timeout", "60",
 
 
264
  # Retry logic
265
  "--retries", "15",
266
  "--fragment-retries", "15",
267
  "--retry-sleep", "exp=2:60",
268
+ "--sleep-requests", "2",
269
  # Output
270
  "-o", raw_download_path,
271
  url
 
273
 
274
  result = subprocess.run(download_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=480)
275
  stderr_text = result.stderr.decode('utf-8', errors='ignore')
 
276
 
277
  if result.returncode != 0 or not os.path.exists(raw_download_path) or os.path.getsize(raw_download_path) == 0:
278
  if 'SSL' in stderr_text or 'EOF' in stderr_text or 'network' in stderr_text.lower():
279
+ err = 'YouTube is blocking server downloads. This is a YouTube restriction on server/datacenter IPs. Try: 1) A less popular/unlisted video, 2) A short clip under 3 min.'
280
+ elif 'Private' in stderr_text or 'members-only' in stderr_text:
281
  err = 'This video is private or members-only. Only public videos can be downloaded.'
282
  elif 'removed' in stderr_text or 'unavailable' in stderr_text or 'not available' in stderr_text:
283
  err = 'This video is unavailable or has been removed from YouTube.'
284
  elif 'Sign in' in stderr_text or 'bot' in stderr_text.lower():
285
+ err = 'YouTube detected bot activity. Try a different less-popular public video.'
286
+ elif 'impersonate' in stderr_text.lower() or 'curl' in stderr_text.lower():
287
+ err = 'Browser impersonation not available. Retrying without it — please try again.'
288
  else:
289
  err = stderr_text[-600:] if stderr_text else 'Unknown download error'
290
  return jsonify({'success': False, 'error': f'Download failed: {err}'}), 500
requirements.txt CHANGED
@@ -7,3 +7,4 @@ numpy
7
  Pillow>=10.0.0
8
  requests
9
  gunicorn
 
 
7
  Pillow>=10.0.0
8
  requests
9
  gunicorn
10
+ curl-cffi>=0.7.0