jpjp9292 commited on
Commit
e9a55dc
β€’
1 Parent(s): 3351799

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -94
app.py CHANGED
@@ -216,9 +216,9 @@ import streamlit as st
216
  import yt_dlp
217
  import os
218
  from pathlib import Path
219
- import json
220
  from http.cookiejar import MozillaCookieJar
221
- from datetime import datetime
 
222
 
223
  # Constants
224
  COOKIES_FILE = 'youtube.com_cookies.txt'
@@ -231,79 +231,99 @@ st.title("YouTube Video Downloader πŸ“Ί")
231
  # Create output directory if it doesn't exist
232
  OUTPUT_DIR.mkdir(exist_ok=True)
233
 
 
 
 
 
 
 
 
 
 
 
 
234
  def validate_cookies():
235
- """μΏ ν‚€ 파일 μœ νš¨μ„± 검사"""
236
  if not os.path.exists(COOKIES_FILE):
237
  return False, "Cookie file not found"
238
 
239
  try:
240
  cookie_jar = MozillaCookieJar(COOKIES_FILE)
241
  cookie_jar.load()
242
-
243
- # Check for essential YouTube cookies
244
- essential_cookies = ['CONSENT', 'LOGIN_INFO', 'PREF']
245
- found_cookies = [cookie.name for cookie in cookie_jar]
246
-
247
- missing_cookies = [cookie for cookie in essential_cookies if cookie not in found_cookies]
248
- if missing_cookies:
249
- return False, f"Missing essential cookies: {', '.join(missing_cookies)}"
250
-
251
- return True, "Cookies valid"
252
- except Exception as e:
253
- return False, f"Cookie validation error: {str(e)}"
254
-
255
- def get_video_info(url):
256
- """λ™μ˜μƒ 정보 미리보기 μΆ”μΆœ"""
257
- ydl_opts = {
258
- 'quiet': True,
259
- 'no_warnings': True,
260
- 'extract_flat': True,
261
- 'cookiefile': COOKIES_FILE,
262
- }
263
-
264
- try:
265
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
266
- return ydl.extract_info(url, download=False)
267
  except Exception as e:
268
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
270
  def download_video(url):
271
  try:
272
  ydl_opts = {
273
- 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', # Prefer MP4
274
  'outtmpl': str(OUTPUT_DIR / '%(title)s.%(ext)s'),
275
  'merge_output_format': 'mp4',
276
 
277
- # Cookie and authentication settings
278
  'cookiefile': COOKIES_FILE,
279
- 'cookiesfrombrowser': ('chrome',), # Also try to get cookies from Chrome
280
 
281
- # Enhanced options
282
  'quiet': True,
283
  'no_warnings': True,
284
  'extract_flat': False,
285
  'socket_timeout': 30,
286
  'retries': 10,
287
  'fragment_retries': 10,
288
- 'file_access_retries': 10,
289
 
290
- # Headers
291
  'headers': {
292
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
293
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
294
- 'Accept-Language': 'en-us,en;q=0.5',
295
- 'Accept-Encoding': 'gzip,deflate',
296
- 'DNT': '1',
297
  'Upgrade-Insecure-Requests': '1',
 
 
 
 
 
298
  },
299
 
300
- # Additional options
301
- 'age_limit': None, # Try to bypass age restriction
302
  'geo_bypass': True,
303
  'geo_bypass_country': 'US',
 
 
304
  }
305
 
306
- # Progress tracking
307
  progress_bar = st.progress(0)
308
  status_text = st.empty()
309
 
@@ -314,69 +334,45 @@ def download_video(url):
314
  progress_bar.progress(progress)
315
  status_text.text(f"Downloading: {progress:.1%} | Speed: {d.get('speed_str', 'N/A')} | ETA: {d.get('eta_str', 'N/A')}")
316
  except:
317
- status_text.text(f"Downloading... Size: {d.get('total_bytes_str', 'unknown')} | Speed: {d.get('speed_str', 'N/A')}")
318
  elif d['status'] == 'finished':
319
  progress_bar.progress(1.0)
320
- status_text.text("Processing downloaded files...")
321
 
322
  ydl_opts['progress_hooks'] = [progress_hook]
323
 
324
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
325
- info = ydl.extract_info(url, download=True)
326
- filename = ydl.prepare_filename(info)
327
- return filename, info
328
 
329
- except yt_dlp.utils.DownloadError as e:
330
- if "Sign in to confirm your age" in str(e):
331
- raise Exception("This video requires age verification. Please ensure you're logged in through the cookies file.")
332
- elif "The uploader has not made this video available in your country" in str(e):
333
- raise Exception("This video is not available in your country. Try using a VPN.")
334
- else:
335
- raise Exception(f"Download error: {str(e)}")
336
  except Exception as e:
337
- raise Exception(f"An unexpected error occurred: {str(e)}")
338
 
339
- # Check cookie status at startup
340
  cookie_valid, cookie_message = validate_cookies()
341
  if not cookie_valid:
342
  st.warning(f"⚠️ Cookie Issue: {cookie_message}")
343
  else:
344
  st.success("βœ… Cookies loaded successfully")
345
 
346
- # Video URL input
347
  video_url = st.text_input("Enter YouTube Video URL:", placeholder="https://www.youtube.com/watch?v=...")
348
 
349
- # Preview button
350
- if video_url and st.button("Preview Video Info"):
351
- with st.spinner("Fetching video information..."):
352
- info = get_video_info(video_url)
353
- if info:
354
- st.write("**Video Information:**")
355
- st.write(f"Title: {info.get('title', 'N/A')}")
356
- st.write(f"Duration: {info.get('duration_string', 'N/A')}")
357
- st.write(f"View Count: {info.get('view_count', 'N/A'):,}")
358
- st.write(f"Upload Date: {info.get('upload_date', 'N/A')}")
359
-
360
- # Download button
361
  if st.button("Download Video"):
362
  if not video_url:
363
  st.warning("⚠️ Please enter a valid YouTube URL.")
364
  elif not cookie_valid:
365
- st.error("❌ Cannot proceed without valid cookies. Please check your cookie file.")
366
  else:
367
  try:
368
  with st.spinner("Preparing download..."):
369
  downloaded_file_path, video_info = download_video(video_url)
370
 
371
  if downloaded_file_path and os.path.exists(downloaded_file_path):
372
- # Add file info
373
  file_size = os.path.getsize(downloaded_file_path)
374
  st.info(f"""
375
  **Download Complete!**
376
  - File: {os.path.basename(downloaded_file_path)}
377
  - Size: {file_size / (1024*1024):.1f} MB
378
- - Format: {video_info.get('format', 'N/A')}
379
- - Resolution: {video_info.get('resolution', 'N/A')}
380
  """)
381
 
382
  with open(downloaded_file_path, 'rb') as file:
@@ -391,25 +387,23 @@ if st.button("Download Video"):
391
  except Exception as e:
392
  st.error(f"❌ {str(e)}")
393
 
394
- # Enhanced help section
395
- with st.expander("ℹ️ Help & Cookie Information"):
396
  st.markdown("""
397
- **Cookie File Status:**
398
- - Location: `youtube.com_cookies.txt`
399
- - Valid: {'βœ…' if cookie_valid else '❌'}
400
- - Message: {cookie_message}
401
-
402
- **Common Issues:**
403
- 1. Age-Restricted Videos:
404
- - Ensure you're logged into YouTube when exporting cookies
405
- - The cookie file must contain valid authentication tokens
406
-
407
- 2. Region-Restricted Content:
408
- - The app attempts to bypass region restrictions automatically
409
- - Consider using a VPN if download fails
410
 
411
- 3. Cookie-Related Problems:
412
- - Use a browser extension (e.g., "Get cookies.txt") to export cookies
413
- - Make sure you're logged into YouTube before exporting
414
- - Cookie file must be in Mozilla/Netscape format
 
 
 
 
 
 
 
 
 
 
415
  """)
 
216
  import yt_dlp
217
  import os
218
  from pathlib import Path
 
219
  from http.cookiejar import MozillaCookieJar
220
+ import random
221
+ import time
222
 
223
  # Constants
224
  COOKIES_FILE = 'youtube.com_cookies.txt'
 
231
  # Create output directory if it doesn't exist
232
  OUTPUT_DIR.mkdir(exist_ok=True)
233
 
234
+ def get_random_user_agent():
235
+ """랜덀 User-Agent 생성"""
236
+ user_agents = [
237
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
238
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
239
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
240
+ 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
241
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0'
242
+ ]
243
+ return random.choice(user_agents)
244
+
245
  def validate_cookies():
246
+ """μΏ ν‚€ 파일 μœ νš¨μ„± 검사 및 κ°±μ‹ """
247
  if not os.path.exists(COOKIES_FILE):
248
  return False, "Cookie file not found"
249
 
250
  try:
251
  cookie_jar = MozillaCookieJar(COOKIES_FILE)
252
  cookie_jar.load()
253
+ return True, "Cookies loaded successfully"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  except Exception as e:
255
+ return False, f"Cookie error: {str(e)}"
256
+
257
+ def download_with_retry(url, ydl_opts, max_retries=3, delay=5):
258
+ """μž¬μ‹œλ„ 둜직이 ν¬ν•¨λœ λ‹€μš΄λ‘œλ“œ ν•¨μˆ˜"""
259
+ for attempt in range(max_retries):
260
+ try:
261
+ # 맀 μ‹œλ„λ§ˆλ‹€ μƒˆλ‘œμš΄ User-Agent μ‚¬μš©
262
+ ydl_opts['headers']['User-Agent'] = get_random_user_agent()
263
+
264
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
265
+ info = ydl.extract_info(url, download=True)
266
+ filename = ydl.prepare_filename(info)
267
+ return filename, info
268
+
269
+ except yt_dlp.utils.DownloadError as e:
270
+ if "Sign in to confirm you're not a bot" in str(e):
271
+ if attempt < max_retries - 1:
272
+ st.warning(f"Bot detection encountered. Retrying in {delay} seconds... (Attempt {attempt + 1}/{max_retries})")
273
+ time.sleep(delay)
274
+ delay *= 2 # μ§€μˆ˜ λ°±μ˜€ν”„
275
+ continue
276
+ raise e
277
+ except Exception as e:
278
+ if attempt < max_retries - 1:
279
+ st.warning(f"Error occurred. Retrying... (Attempt {attempt + 1}/{max_retries})")
280
+ time.sleep(delay)
281
+ continue
282
+ raise e
283
 
284
  def download_video(url):
285
  try:
286
  ydl_opts = {
287
+ 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
288
  'outtmpl': str(OUTPUT_DIR / '%(title)s.%(ext)s'),
289
  'merge_output_format': 'mp4',
290
 
291
+ # μΏ ν‚€ 및 인증 μ„€μ •
292
  'cookiefile': COOKIES_FILE,
293
+ 'cookiesfrombrowser': ('chrome',),
294
 
295
+ # ν–₯μƒλœ μ˜΅μ…˜
296
  'quiet': True,
297
  'no_warnings': True,
298
  'extract_flat': False,
299
  'socket_timeout': 30,
300
  'retries': 10,
301
  'fragment_retries': 10,
 
302
 
303
+ # ν–₯μƒλœ 헀더
304
  'headers': {
305
+ 'User-Agent': get_random_user_agent(),
306
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
307
+ 'Accept-Language': 'en-US,en;q=0.5',
308
+ 'Accept-Encoding': 'gzip, deflate, br',
309
+ 'Connection': 'keep-alive',
310
  'Upgrade-Insecure-Requests': '1',
311
+ 'Sec-Fetch-Dest': 'document',
312
+ 'Sec-Fetch-Mode': 'navigate',
313
+ 'Sec-Fetch-Site': 'none',
314
+ 'Sec-Fetch-User': '?1',
315
+ 'Cache-Control': 'max-age=0',
316
  },
317
 
318
+ # μΆ”κ°€ μ˜΅μ…˜
319
+ 'age_limit': None,
320
  'geo_bypass': True,
321
  'geo_bypass_country': 'US',
322
+ 'sleep_interval': 2, # μš”μ²­ 사이 λŒ€κΈ° μ‹œκ°„
323
+ 'max_sleep_interval': 5,
324
  }
325
 
326
+ # 진행 상황 ν‘œμ‹œ
327
  progress_bar = st.progress(0)
328
  status_text = st.empty()
329
 
 
334
  progress_bar.progress(progress)
335
  status_text.text(f"Downloading: {progress:.1%} | Speed: {d.get('speed_str', 'N/A')} | ETA: {d.get('eta_str', 'N/A')}")
336
  except:
337
+ status_text.text(f"Downloading... Speed: {d.get('speed_str', 'N/A')}")
338
  elif d['status'] == 'finished':
339
  progress_bar.progress(1.0)
340
+ status_text.text("Processing...")
341
 
342
  ydl_opts['progress_hooks'] = [progress_hook]
343
 
344
+ return download_with_retry(url, ydl_opts)
 
 
 
345
 
 
 
 
 
 
 
 
346
  except Exception as e:
347
+ raise Exception(f"Download error: {str(e)}")
348
 
349
+ # μΏ ν‚€ μƒνƒœ 확인
350
  cookie_valid, cookie_message = validate_cookies()
351
  if not cookie_valid:
352
  st.warning(f"⚠️ Cookie Issue: {cookie_message}")
353
  else:
354
  st.success("βœ… Cookies loaded successfully")
355
 
356
+ # λΉ„λ””μ˜€ URL μž…λ ₯
357
  video_url = st.text_input("Enter YouTube Video URL:", placeholder="https://www.youtube.com/watch?v=...")
358
 
359
+ # λ‹€μš΄λ‘œλ“œ λ²„νŠΌ
 
 
 
 
 
 
 
 
 
 
 
360
  if st.button("Download Video"):
361
  if not video_url:
362
  st.warning("⚠️ Please enter a valid YouTube URL.")
363
  elif not cookie_valid:
364
+ st.error("❌ Cannot proceed without valid cookies.")
365
  else:
366
  try:
367
  with st.spinner("Preparing download..."):
368
  downloaded_file_path, video_info = download_video(video_url)
369
 
370
  if downloaded_file_path and os.path.exists(downloaded_file_path):
 
371
  file_size = os.path.getsize(downloaded_file_path)
372
  st.info(f"""
373
  **Download Complete!**
374
  - File: {os.path.basename(downloaded_file_path)}
375
  - Size: {file_size / (1024*1024):.1f} MB
 
 
376
  """)
377
 
378
  with open(downloaded_file_path, 'rb') as file:
 
387
  except Exception as e:
388
  st.error(f"❌ {str(e)}")
389
 
390
+ # Help μ„Ήμ…˜
391
+ with st.expander("ℹ️ Troubleshooting Guide"):
392
  st.markdown("""
393
+ **If you encounter 'Sign in to confirm you're not a bot' error:**
 
 
 
 
 
 
 
 
 
 
 
 
394
 
395
+ 1. Cookie Solution:
396
+ - Make sure you're logged into YouTube in your browser
397
+ - Install 'Get cookies.txt' or similar extension
398
+ - Export fresh cookies and replace the existing cookie file
399
+
400
+ 2. General Tips:
401
+ - Wait a few minutes between download attempts
402
+ - Try using a different video URL
403
+ - Clear your browser cache before exporting cookies
404
+
405
+ 3. Advanced Tips:
406
+ - The app automatically retries downloads with different settings
407
+ - Each retry uses a different User-Agent to avoid detection
408
+ - Built-in delays help avoid triggering YouTube's protection
409
  """)