Fred808 commited on
Commit
d3f13be
·
verified ·
1 Parent(s): 07760d5

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +63 -26
main.py CHANGED
@@ -31,13 +31,13 @@ logger = logging.getLogger(__name__)
31
  # Pydantic models
32
  class VideoInfoRequest(BaseModel):
33
  url: HttpUrl
34
- use_cookies: bool = False
35
 
36
  class DownloadRequest(BaseModel):
37
  url: HttpUrl
38
  quality: str = "best"
39
  audio_only: bool = False
40
- use_cookies: bool = False
41
 
42
  class VideoInfo(BaseModel):
43
  title: str
@@ -70,7 +70,7 @@ class HealthResponse(BaseModel):
70
  app = FastAPI(
71
  title="Cookie-Enhanced YouTube Video Downloader",
72
  description="Download YouTube videos with proper cookie support and troubleshooting",
73
- version="3.0.0",
74
  docs_url="/docs",
75
  redoc_url="/redoc"
76
  )
@@ -175,6 +175,10 @@ class CookieManager:
175
  if validation["valid"]:
176
  return str(self.cookie_file)
177
  return None
 
 
 
 
178
 
179
  class EnhancedYouTubeDownloader:
180
  """Enhanced YouTube downloader with cookie support and troubleshooting"""
@@ -217,15 +221,24 @@ class EnhancedYouTubeDownloader:
217
  logger.error(f"Failed to install yt-dlp: {e}")
218
  raise RuntimeError("Could not install yt-dlp")
219
 
220
- def _build_command(self, base_cmd: List[str], use_cookies: bool = False) -> List[str]:
 
 
 
 
 
 
 
221
  """Build yt-dlp command with proper options"""
222
  cmd = base_cmd.copy()
223
 
224
  # Add user agent
225
  cmd.extend(['--user-agent', random.choice(self.user_agents)])
226
 
227
- # Cookie handling
228
- if use_cookies:
 
 
229
  cookie_path = self.cookie_manager.get_cookie_path()
230
  if cookie_path:
231
  cmd.extend(['--cookies', cookie_path])
@@ -252,9 +265,9 @@ class EnhancedYouTubeDownloader:
252
  '--add-header', 'Upgrade-Insecure-Requests:1',
253
  ])
254
 
255
- return cmd
256
 
257
- def get_video_info(self, url: str, use_cookies: bool = False, retry_count: int = 0) -> Optional[Dict[str, Any]]:
258
  """Get video information with cookie support"""
259
  max_retries = 3
260
 
@@ -266,9 +279,9 @@ class EnhancedYouTubeDownloader:
266
  str(url)
267
  ]
268
 
269
- cmd = self._build_command(base_cmd, use_cookies)
270
 
271
- logger.info(f"Getting video info (attempt {retry_count + 1}, cookies: {use_cookies})")
272
 
273
  result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=60)
274
  video_info = json.loads(result.stdout)
@@ -298,8 +311,9 @@ class EnhancedYouTubeDownloader:
298
  return self.get_video_info(url, use_cookies, retry_count + 1)
299
 
300
  elif "sign in" in error_msg or "bot" in error_msg:
301
- if not use_cookies and retry_count == 0:
302
- logger.warning("Bot detection triggered, retrying with cookies if available")
 
303
  return self.get_video_info(url, True, retry_count + 1)
304
  elif retry_count < max_retries:
305
  wait_time = (retry_count + 1) * 60
@@ -307,7 +321,7 @@ class EnhancedYouTubeDownloader:
307
  time.sleep(wait_time)
308
  return self.get_video_info(url, use_cookies, retry_count + 1)
309
 
310
- elif "cookies" in error_msg and use_cookies:
311
  logger.error("Cookie-related error - cookies may be expired or invalid")
312
  # Try without cookies as fallback
313
  if retry_count == 0:
@@ -325,7 +339,7 @@ class EnhancedYouTubeDownloader:
325
  return None
326
 
327
  def download_video(self, url: str, quality: str = "best",
328
- audio_only: bool = False, use_cookies: bool = False,
329
  retry_count: int = 0) -> Optional[str]:
330
  """Download video with cookie support"""
331
  max_retries = 2
@@ -350,9 +364,9 @@ class EnhancedYouTubeDownloader:
350
 
351
  base_cmd.append(str(url))
352
 
353
- cmd = self._build_command(base_cmd, use_cookies)
354
 
355
- logger.info(f"Downloading video (attempt {retry_count + 1}, cookies: {use_cookies})")
356
 
357
  result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=300)
358
 
@@ -372,8 +386,9 @@ class EnhancedYouTubeDownloader:
372
  if ("429" in error_msg or "too many requests" in error_msg or
373
  "sign in" in error_msg or "bot" in error_msg):
374
 
375
- if not use_cookies and retry_count == 0:
376
- logger.warning("Download blocked, retrying with cookies if available")
 
377
  return self.download_video(url, quality, audio_only, True, retry_count + 1)
378
  elif retry_count < max_retries:
379
  wait_time = (retry_count + 1) * 60
@@ -475,6 +490,14 @@ async def read_root():
475
  margin: 20px 0;
476
  color: #155724;
477
  }
 
 
 
 
 
 
 
 
478
  input[type="file"] {
479
  margin: 10px 0;
480
  }
@@ -487,6 +510,11 @@ async def read_root():
487
  <p>Upload your YouTube cookies for better success rates</p>
488
  </div>
489
 
 
 
 
 
 
490
  <div class="warning">
491
  <strong>⚠️ Cookie Issues?</strong> If your cookies aren't working, they might be:
492
  <ul>
@@ -577,7 +605,7 @@ async def upload_cookies(cookie_file: UploadFile = File(...)):
577
  validation = downloader.cookie_manager.validate_cookies()
578
  return {
579
  "success": True,
580
- "message": f"Cookies uploaded successfully. Found {validation.get('youtube_cookies', 0)} YouTube cookies.",
581
  "validation": validation
582
  }
583
  else:
@@ -599,6 +627,8 @@ async def cookie_status():
599
  validation = downloader.cookie_manager.validate_cookies()
600
  return {
601
  "cookie_file_exists": downloader.cookie_manager.cookie_file.exists(),
 
 
602
  "validation": validation
603
  }
604
 
@@ -612,6 +642,7 @@ async def health_check():
612
  yt_dlp_available = False
613
 
614
  strategies = [
 
615
  "Cookie Support",
616
  "User-Agent Rotation",
617
  "Smart Retry Logic",
@@ -630,7 +661,7 @@ async def health_check():
630
 
631
  @app.post("/video/info", response_model=Dict[str, Any])
632
  async def get_video_info(request: VideoInfoRequest):
633
- """Get video information with cookie support"""
634
  try:
635
  url_str = str(request.url)
636
  if not any(domain in url_str for domain in ['youtube.com', 'youtu.be']):
@@ -641,11 +672,15 @@ async def get_video_info(request: VideoInfoRequest):
641
  executor,
642
  downloader.get_video_info,
643
  url_str,
644
- request.use_cookies
645
  )
646
 
647
  if info:
648
- return {"success": True, "info": info}
 
 
 
 
649
  else:
650
  raise HTTPException(
651
  status_code=503,
@@ -660,7 +695,7 @@ async def get_video_info(request: VideoInfoRequest):
660
 
661
  @app.post("/video/download", response_model=DownloadResponse)
662
  async def download_video(request: DownloadRequest, background_tasks: BackgroundTasks):
663
- """Download video with cookie support"""
664
  try:
665
  url_str = str(request.url)
666
  if not any(domain in url_str for domain in ['youtube.com', 'youtu.be']):
@@ -672,7 +707,7 @@ async def download_video(request: DownloadRequest, background_tasks: BackgroundT
672
  executor,
673
  downloader.get_video_info,
674
  url_str,
675
- request.use_cookies
676
  )
677
  if not info:
678
  raise HTTPException(
@@ -687,7 +722,7 @@ async def download_video(request: DownloadRequest, background_tasks: BackgroundT
687
  url_str,
688
  request.quality,
689
  request.audio_only,
690
- request.use_cookies
691
  )
692
 
693
  if downloaded_file:
@@ -697,9 +732,11 @@ async def download_video(request: DownloadRequest, background_tasks: BackgroundT
697
  # Schedule cleanup after 2 hours
698
  background_tasks.add_task(cleanup_file, downloaded_file, delay=7200)
699
 
 
 
700
  return DownloadResponse(
701
  success=True,
702
- message="Video downloaded successfully with cookie support",
703
  filename=filename,
704
  file_size=file_size,
705
  video_info=VideoInfo(**info),
 
31
  # Pydantic models
32
  class VideoInfoRequest(BaseModel):
33
  url: HttpUrl
34
+ use_cookies: bool = None # Changed to None to allow auto-detection
35
 
36
  class DownloadRequest(BaseModel):
37
  url: HttpUrl
38
  quality: str = "best"
39
  audio_only: bool = False
40
+ use_cookies: bool = None # Changed to None to allow auto-detection
41
 
42
  class VideoInfo(BaseModel):
43
  title: str
 
70
  app = FastAPI(
71
  title="Cookie-Enhanced YouTube Video Downloader",
72
  description="Download YouTube videos with proper cookie support and troubleshooting",
73
+ version="3.1.0",
74
  docs_url="/docs",
75
  redoc_url="/redoc"
76
  )
 
175
  if validation["valid"]:
176
  return str(self.cookie_file)
177
  return None
178
+
179
+ def has_valid_cookies(self) -> bool:
180
+ """Check if valid cookies are available"""
181
+ return self.get_cookie_path() is not None
182
 
183
  class EnhancedYouTubeDownloader:
184
  """Enhanced YouTube downloader with cookie support and troubleshooting"""
 
221
  logger.error(f"Failed to install yt-dlp: {e}")
222
  raise RuntimeError("Could not install yt-dlp")
223
 
224
+ def _should_use_cookies(self, use_cookies: Optional[bool]) -> bool:
225
+ """Determine whether to use cookies based on request and availability"""
226
+ if use_cookies is None:
227
+ # Auto-detect: use cookies if available
228
+ return self.cookie_manager.has_valid_cookies()
229
+ return use_cookies and self.cookie_manager.has_valid_cookies()
230
+
231
+ def _build_command(self, base_cmd: List[str], use_cookies: Optional[bool] = None) -> List[str]:
232
  """Build yt-dlp command with proper options"""
233
  cmd = base_cmd.copy()
234
 
235
  # Add user agent
236
  cmd.extend(['--user-agent', random.choice(self.user_agents)])
237
 
238
+ # Cookie handling with improved logic
239
+ should_use_cookies = self._should_use_cookies(use_cookies)
240
+
241
+ if should_use_cookies:
242
  cookie_path = self.cookie_manager.get_cookie_path()
243
  if cookie_path:
244
  cmd.extend(['--cookies', cookie_path])
 
265
  '--add-header', 'Upgrade-Insecure-Requests:1',
266
  ])
267
 
268
+ return cmd, should_use_cookies
269
 
270
+ def get_video_info(self, url: str, use_cookies: Optional[bool] = None, retry_count: int = 0) -> Optional[Dict[str, Any]]:
271
  """Get video information with cookie support"""
272
  max_retries = 3
273
 
 
279
  str(url)
280
  ]
281
 
282
+ cmd, actual_cookie_usage = self._build_command(base_cmd, use_cookies)
283
 
284
+ logger.info(f"Getting video info (attempt {retry_count + 1}, cookies: {actual_cookie_usage})")
285
 
286
  result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=60)
287
  video_info = json.loads(result.stdout)
 
311
  return self.get_video_info(url, use_cookies, retry_count + 1)
312
 
313
  elif "sign in" in error_msg or "bot" in error_msg:
314
+ # If not using cookies and we have them available, try with cookies
315
+ if not self._should_use_cookies(use_cookies) and self.cookie_manager.has_valid_cookies() and retry_count == 0:
316
+ logger.warning("Bot detection triggered, retrying with cookies")
317
  return self.get_video_info(url, True, retry_count + 1)
318
  elif retry_count < max_retries:
319
  wait_time = (retry_count + 1) * 60
 
321
  time.sleep(wait_time)
322
  return self.get_video_info(url, use_cookies, retry_count + 1)
323
 
324
+ elif "cookies" in error_msg and self._should_use_cookies(use_cookies):
325
  logger.error("Cookie-related error - cookies may be expired or invalid")
326
  # Try without cookies as fallback
327
  if retry_count == 0:
 
339
  return None
340
 
341
  def download_video(self, url: str, quality: str = "best",
342
+ audio_only: bool = False, use_cookies: Optional[bool] = None,
343
  retry_count: int = 0) -> Optional[str]:
344
  """Download video with cookie support"""
345
  max_retries = 2
 
364
 
365
  base_cmd.append(str(url))
366
 
367
+ cmd, actual_cookie_usage = self._build_command(base_cmd, use_cookies)
368
 
369
+ logger.info(f"Downloading video (attempt {retry_count + 1}, cookies: {actual_cookie_usage})")
370
 
371
  result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=300)
372
 
 
386
  if ("429" in error_msg or "too many requests" in error_msg or
387
  "sign in" in error_msg or "bot" in error_msg):
388
 
389
+ # If not using cookies and we have them available, try with cookies
390
+ if not self._should_use_cookies(use_cookies) and self.cookie_manager.has_valid_cookies() and retry_count == 0:
391
+ logger.warning("Download blocked, retrying with cookies")
392
  return self.download_video(url, quality, audio_only, True, retry_count + 1)
393
  elif retry_count < max_retries:
394
  wait_time = (retry_count + 1) * 60
 
490
  margin: 20px 0;
491
  color: #155724;
492
  }
493
+ .info {
494
+ background: #d1ecf1;
495
+ border: 1px solid #bee5eb;
496
+ border-radius: 5px;
497
+ padding: 15px;
498
+ margin: 20px 0;
499
+ color: #0c5460;
500
+ }
501
  input[type="file"] {
502
  margin: 10px 0;
503
  }
 
510
  <p>Upload your YouTube cookies for better success rates</p>
511
  </div>
512
 
513
+ <div class="info">
514
+ <strong>🔄 Auto-Cookie Detection:</strong> This version automatically uses cookies when available.
515
+ You no longer need to manually enable cookies in API requests!
516
+ </div>
517
+
518
  <div class="warning">
519
  <strong>⚠️ Cookie Issues?</strong> If your cookies aren't working, they might be:
520
  <ul>
 
605
  validation = downloader.cookie_manager.validate_cookies()
606
  return {
607
  "success": True,
608
+ "message": f"Cookies uploaded successfully. Found {validation.get('youtube_cookies', 0)} YouTube cookies. Auto-detection enabled.",
609
  "validation": validation
610
  }
611
  else:
 
627
  validation = downloader.cookie_manager.validate_cookies()
628
  return {
629
  "cookie_file_exists": downloader.cookie_manager.cookie_file.exists(),
630
+ "has_valid_cookies": downloader.cookie_manager.has_valid_cookies(),
631
+ "auto_detection_enabled": True,
632
  "validation": validation
633
  }
634
 
 
642
  yt_dlp_available = False
643
 
644
  strategies = [
645
+ "Auto Cookie Detection",
646
  "Cookie Support",
647
  "User-Agent Rotation",
648
  "Smart Retry Logic",
 
661
 
662
  @app.post("/video/info", response_model=Dict[str, Any])
663
  async def get_video_info(request: VideoInfoRequest):
664
+ """Get video information with automatic cookie detection"""
665
  try:
666
  url_str = str(request.url)
667
  if not any(domain in url_str for domain in ['youtube.com', 'youtu.be']):
 
672
  executor,
673
  downloader.get_video_info,
674
  url_str,
675
+ request.use_cookies # This can be None for auto-detection
676
  )
677
 
678
  if info:
679
+ return {
680
+ "success": True,
681
+ "info": info,
682
+ "cookies_used": downloader._should_use_cookies(request.use_cookies)
683
+ }
684
  else:
685
  raise HTTPException(
686
  status_code=503,
 
695
 
696
  @app.post("/video/download", response_model=DownloadResponse)
697
  async def download_video(request: DownloadRequest, background_tasks: BackgroundTasks):
698
+ """Download video with automatic cookie detection"""
699
  try:
700
  url_str = str(request.url)
701
  if not any(domain in url_str for domain in ['youtube.com', 'youtu.be']):
 
707
  executor,
708
  downloader.get_video_info,
709
  url_str,
710
+ request.use_cookies # This can be None for auto-detection
711
  )
712
  if not info:
713
  raise HTTPException(
 
722
  url_str,
723
  request.quality,
724
  request.audio_only,
725
+ request.use_cookies # This can be None for auto-detection
726
  )
727
 
728
  if downloaded_file:
 
732
  # Schedule cleanup after 2 hours
733
  background_tasks.add_task(cleanup_file, downloaded_file, delay=7200)
734
 
735
+ cookies_used = downloader._should_use_cookies(request.use_cookies)
736
+
737
  return DownloadResponse(
738
  success=True,
739
+ message=f"Video downloaded successfully {'with' if cookies_used else 'without'} cookies",
740
  filename=filename,
741
  file_size=file_size,
742
  video_info=VideoInfo(**info),