Spaces:
Runtime error
Runtime error
# import streamlit as st | |
# import yt_dlp | |
# import os | |
# from pathlib import Path | |
# # Set page config | |
# st.set_page_config(page_title="YouTube Video Downloader", page_icon="๐บ") | |
# # Set the title of the app | |
# st.title("YouTube Video Downloader ๐บ") | |
# # Create output directory if it doesn't exist | |
# output_dir = Path("downloads") | |
# output_dir.mkdir(exist_ok=True) | |
# # Input field for YouTube video URL | |
# video_url = st.text_input("Enter YouTube Video URL:", placeholder="https://www.youtube.com/watch?v=...") | |
# # Function to download video | |
# def download_video(url): | |
# try: | |
# ydl_opts = { | |
# 'format': 'bestvideo+bestaudio/best', | |
# 'outtmpl': str(output_dir / '%(title)s.%(ext)s'), | |
# 'merge_output_format': 'webm', | |
# 'quiet': False, # Change to False to see more detailed error output | |
# 'no_warnings': False, | |
# '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', | |
# 'referer': 'https://www.youtube.com/', | |
# 'cookiefile': 'youtube.com_cookies.txt', # Ensure this file path is correct | |
# 'socket_timeout': 30, | |
# 'http_chunk_size': 10485760, # 10MB | |
# 'retries': 10, # Increase retry attempts | |
# 'headers': { | |
# 'Accept-Language': 'en-US,en;q=0.9', | |
# 'Accept-Encoding': 'gzip, deflate, br', | |
# 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', | |
# 'Upgrade-Insecure-Requests': '1', | |
# } | |
# } | |
# # Progress placeholder | |
# progress_bar = st.progress(0) | |
# status_text = st.empty() | |
# def progress_hook(d): | |
# if d['status'] == 'downloading': | |
# try: | |
# progress = d['downloaded_bytes'] / d['total_bytes'] | |
# progress_bar.progress(progress) | |
# status_text.text(f"Downloading: {progress:.1%}") | |
# except: | |
# status_text.text("Downloading... (size unknown)") | |
# elif d['status'] == 'finished': | |
# progress_bar.progress(1.0) | |
# status_text.text("Processing...") | |
# ydl_opts['progress_hooks'] = [progress_hook] | |
# with yt_dlp.YoutubeDL(ydl_opts) as ydl: | |
# info = ydl.extract_info(url, download=True) | |
# filename = ydl.prepare_filename(info) | |
# return filename | |
# except Exception as e: | |
# st.error(f"An error occurred: {str(e)}") | |
# return None | |
# # Download button | |
# if st.button("Download"): | |
# if video_url: | |
# try: | |
# with st.spinner("Preparing download..."): | |
# downloaded_file_path = download_video(video_url) | |
# if downloaded_file_path and os.path.exists(downloaded_file_path): | |
# with open(downloaded_file_path, 'rb') as file: | |
# st.download_button( | |
# label="Click here to download", | |
# data=file, | |
# file_name=os.path.basename(downloaded_file_path), | |
# mime="application/octet-stream" | |
# ) | |
# st.success("โ Download ready!") | |
# else: | |
# st.error("โ Download failed. Please try again.") | |
# except Exception as e: | |
# st.error(f"โ An error occurred: {str(e)}") | |
# else: | |
# st.warning("โ ๏ธ Please enter a valid YouTube URL.") | |
# # Help section | |
# with st.expander("โน๏ธ Help & Troubleshooting"): | |
# st.markdown(""" | |
# **If you're experiencing download issues:** | |
# 1. Cookie Authentication Method: | |
# - Install a browser extension like "Get cookies.txt" | |
# - Visit YouTube and ensure you're logged in | |
# - Export cookies to 'youtube.com_cookies.txt' | |
# - Place the file in the same directory as this app | |
# 2. Alternative Solutions: | |
# - Try different videos | |
# - Check if the video is public/not age-restricted | |
# - Try again later if YouTube is blocking requests | |
# """) | |
# import streamlit as st | |
# import yt_dlp | |
# import os | |
# from pathlib import Path | |
# import time | |
# from datetime import datetime | |
# import json | |
# # Set page config | |
# st.set_page_config(page_title="YouTube Video Downloader", page_icon="๐บ", layout="wide") | |
# # Set the title of the app | |
# st.title("YouTube Video Downloader ๐บ") | |
# # Create output directory if it doesn't exist | |
# output_dir = Path("downloads") | |
# output_dir.mkdir(exist_ok=True) | |
# # Authentication settings | |
# AUTH_CONFIG = { | |
# 'COOKIES_FILE': 'youtube.com_cookies.txt', | |
# 'TOKEN_FILE': 'auth_token.json' | |
# } | |
# def load_auth_token(): | |
# try: | |
# if os.path.exists(AUTH_CONFIG['TOKEN_FILE']): | |
# with open(AUTH_CONFIG['TOKEN_FILE'], 'r') as f: | |
# data = json.load(f) | |
# if datetime.fromisoformat(data['expires']) > datetime.now(): | |
# return data['token'] | |
# except Exception: | |
# pass | |
# return None | |
# def save_auth_token(token): | |
# with open(AUTH_CONFIG['TOKEN_FILE'], 'w') as f: | |
# json.dump({ | |
# 'token': token, | |
# 'expires': (datetime.now().isoformat()) | |
# }, f) | |
# def setup_ydl_options(has_cookies): | |
# opts = { | |
# 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', | |
# 'outtmpl': str(output_dir / '%(title)s.%(ext)s'), | |
# 'merge_output_format': 'mp4', | |
# 'quiet': True, | |
# 'no_warnings': True, | |
# 'extract_flat': False, | |
# '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', | |
# 'referer': 'https://www.youtube.com/', | |
# 'http_chunk_size': 10485760, | |
# 'retries': 3, | |
# 'file_access_retries': 3, | |
# 'fragment_retries': 3, | |
# 'skip_unavailable_fragments': True, | |
# 'abort_on_unavailable_fragment': False, | |
# } | |
# # Add cookies file if available | |
# if has_cookies: | |
# opts['cookiefile'] = AUTH_CONFIG['COOKIES_FILE'] | |
# # Add authentication token if available | |
# token = load_auth_token() | |
# if token: | |
# opts['headers'] = { | |
# 'Authorization': f'Bearer {token}' | |
# } | |
# return opts | |
# def download_video(url, progress_callback): | |
# max_retries = 3 | |
# retry_count = 0 | |
# while retry_count < max_retries: | |
# try: | |
# has_cookies = os.path.exists(AUTH_CONFIG['COOKIES_FILE']) | |
# ydl_opts = setup_ydl_options(has_cookies) | |
# # Add progress hooks | |
# def progress_hook(d): | |
# if d['status'] == 'downloading': | |
# try: | |
# progress = d['downloaded_bytes'] / d['total_bytes'] | |
# progress_callback(progress, f"Downloading: {progress:.1%}") | |
# except: | |
# progress_callback(0, "Downloading... (size unknown)") | |
# elif d['status'] == 'finished': | |
# progress_callback(1.0, "Processing...") | |
# ydl_opts['progress_hooks'] = [progress_hook] | |
# with yt_dlp.YoutubeDL(ydl_opts) as ydl: | |
# info = ydl.extract_info(url, download=True) | |
# filename = ydl.prepare_filename(info) | |
# return filename, None | |
# except yt_dlp.utils.ExtractorError as e: | |
# if "Sign in to confirm you're not a bot" in str(e): | |
# retry_count += 1 | |
# if retry_count < max_retries: | |
# time.sleep(5) # Wait before retry | |
# continue | |
# return None, "Bot detection triggered. Please try again later or use authentication." | |
# return None, f"Video extraction failed: {str(e)}" | |
# except Exception as e: | |
# return None, f"Download failed: {str(e)}" | |
# return None, "Maximum retries reached. Please try again later." | |
# # Main UI | |
# col1, col2 = st.columns([2, 1]) | |
# with col1: | |
# video_url = st.text_input("Enter YouTube Video URL:", placeholder="https://www.youtube.com/watch?v=...") | |
# if st.button("Download", type="primary"): | |
# if video_url: | |
# progress_bar = st.progress(0) | |
# status_text = st.empty() | |
# def update_progress(progress, status): | |
# progress_bar.progress(progress) | |
# status_text.text(status) | |
# downloaded_file, error = download_video(video_url, update_progress) | |
# if downloaded_file and os.path.exists(downloaded_file): | |
# with open(downloaded_file, 'rb') as file: | |
# st.download_button( | |
# label="โฌ๏ธ Download Video", | |
# data=file, | |
# file_name=os.path.basename(downloaded_file), | |
# mime="video/mp4" | |
# ) | |
# st.success("โ Download ready!") | |
# else: | |
# st.error(f"โ {error}") | |
# else: | |
# st.warning("โ ๏ธ Please enter a valid YouTube URL.") | |
# with col2: | |
# with st.expander("โ๏ธ Settings & Information"): | |
# st.markdown(""" | |
# **Authentication Status:** | |
# """) | |
# if os.path.exists(AUTH_CONFIG['COOKIES_FILE']): | |
# st.success("โ Cookie authentication available") | |
# else: | |
# st.warning(""" | |
# โ ๏ธ No cookie authentication configured | |
# To enable cookie authentication: | |
# 1. Export cookies from your browser | |
# 2. Save as 'youtube.com_cookies.txt' in the app directory | |
# """) | |
# st.markdown(""" | |
# **Download Options:** | |
# - Videos are downloaded in best available quality | |
# - Format: MP4 (when available) | |
# - Automatic quality selection | |
# """) | |
# with st.expander("โ Help & Troubleshooting"): | |
# st.markdown(""" | |
# **Common Issues & Solutions:** | |
# 1. **Bot Detection:** | |
# - The app implements automatic retries | |
# - Use cookie authentication for better success rate | |
# - Wait a few minutes between attempts | |
# 2. **Download Fails:** | |
# - Verify the video is public | |
# - Check your internet connection | |
# - Try a different video | |
# - Clear browser cache and cookies | |
# 3. **Quality Issues:** | |
# - The app automatically selects the best available quality | |
# - Some videos may have quality restrictions | |
# - Premium content may require authentication | |
# **Need More Help?** | |
# - Check if the video is available in your region | |
# - Verify YouTube's terms of service | |
# - Consider using cookie authentication | |
# """) | |
import streamlit as st | |
import yt_dlp | |
import os | |
from pathlib import Path | |
import time | |
import random | |
from datetime import datetime | |
import json | |
import requests | |
from fake_useragent import UserAgent | |
import http.cookiejar as cookielib | |
# Set page config | |
st.set_page_config(page_title="YouTube Video Downloader", page_icon="๐บ", layout="wide") | |
st.title("YouTube Video Downloader ๐บ") | |
# Constants and Configurations | |
class Config: | |
OUTPUT_DIR = Path("downloads") | |
COOKIES_FILE = 'youtube.com_cookies.txt' | |
TOKEN_FILE = 'auth_token.json' | |
MAX_RETRIES = 5 | |
RETRY_DELAYS = [3, 5, 10, 15, 30] # Progressive delays in seconds | |
HEADERS_POOL = [ | |
{ | |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', | |
'Accept-Language': 'en-US,en;q=0.5', | |
'DNT': '1', | |
'Connection': 'keep-alive', | |
'Upgrade-Insecure-Requests': '1', | |
}, | |
{ | |
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', | |
'Accept-Language': 'en-US,en;q=0.9', | |
'DNT': '1', | |
'Connection': 'keep-alive', | |
} | |
] | |
# Create output directory | |
Config.OUTPUT_DIR.mkdir(exist_ok=True) | |
# Session management | |
class SessionManager: | |
def create_cookie_jar(): | |
return cookielib.MozillaCookieJar(Config.COOKIES_FILE) | |
def get_random_headers(): | |
ua = UserAgent() | |
headers = random.choice(Config.HEADERS_POOL).copy() | |
headers['User-Agent'] = ua.random | |
return headers | |
def get_session(): | |
session = requests.Session() | |
if os.path.exists(Config.COOKIES_FILE): | |
session.cookies = SessionManager.create_cookie_jar() | |
session.cookies.load(ignore_discard=True, ignore_expires=True) | |
session.headers.update(SessionManager.get_random_headers()) | |
return session | |
def get_download_options(session_headers=None): | |
"""Enhanced download options with anti-bot measures""" | |
options = { | |
'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', | |
'outtmpl': str(Config.OUTPUT_DIR / '%(title)s.%(ext)s'), | |
'merge_output_format': 'mp4', | |
'quiet': True, | |
'no_warnings': True, | |
'extract_flat': False, | |
'nocheckcertificate': True, | |
'http_chunk_size': random.randint(10000000, 15000000), # Random chunk size | |
'retries': Config.MAX_RETRIES, | |
'file_access_retries': 3, | |
'fragment_retries': 3, | |
'retry_sleep_functions': {'http': lambda n: random.uniform(1, 5) * n}, | |
'skip_unavailable_fragments': True, | |
'abort_on_unavailable_fragment': False, | |
} | |
if os.path.exists(Config.COOKIES_FILE): | |
options['cookiefile'] = Config.COOKIES_FILE | |
if session_headers: | |
options['headers'] = session_headers | |
return options | |
def download_with_retry(url, progress_callback): | |
"""Enhanced download function with multiple retry strategies""" | |
for attempt in range(Config.MAX_RETRIES): | |
try: | |
session = SessionManager.get_session() | |
ydl_opts = get_download_options(session.headers) | |
def progress_hook(d): | |
if d['status'] == 'downloading': | |
try: | |
progress = d['downloaded_bytes'] / d['total_bytes'] | |
progress_callback(progress, f"Downloading: {progress:.1%}") | |
except: | |
progress_callback(-1, f"Downloading... (Attempt {attempt + 1}/{Config.MAX_RETRIES})") | |
elif d['status'] == 'finished': | |
progress_callback(1.0, "Processing...") | |
ydl_opts['progress_hooks'] = [progress_hook] | |
# Pre-check video availability | |
with yt_dlp.YoutubeDL({'quiet': True}) as ydl: | |
try: | |
ydl.extract_info(url, download=False) | |
except Exception as e: | |
if "This video is not available" in str(e): | |
return None, "Video is not available. It might be private or deleted." | |
# Actual download | |
with yt_dlp.YoutubeDL(ydl_opts) as ydl: | |
info = ydl.extract_info(url, download=True) | |
filename = ydl.prepare_filename(info) | |
return filename, None | |
except yt_dlp.utils.ExtractorError as e: | |
error_msg = str(e) | |
if "Sign in to confirm you're not a bot" in error_msg: | |
delay = Config.RETRY_DELAYS[min(attempt, len(Config.RETRY_DELAYS)-1)] | |
progress_callback(-1, f"Bot detection encountered. Waiting {delay}s before retry...") | |
time.sleep(delay) | |
continue | |
return None, f"Video extraction failed: {error_msg}" | |
except Exception as e: | |
error_msg = str(e) | |
if attempt < Config.MAX_RETRIES - 1: | |
delay = Config.RETRY_DELAYS[attempt] | |
progress_callback(-1, f"Download failed. Retrying in {delay}s... ({attempt + 1}/{Config.MAX_RETRIES})") | |
time.sleep(delay) | |
continue | |
return None, f"Download failed after {Config.MAX_RETRIES} attempts: {error_msg}" | |
return None, "Maximum retries reached. Please try again later." | |
# UI Components | |
def render_main_ui(): | |
col1, col2 = st.columns([2, 1]) | |
with col1: | |
video_url = st.text_input("Enter YouTube Video URL:", placeholder="https://www.youtube.com/watch?v=...") | |
if st.button("Download", type="primary"): | |
if video_url: | |
progress_bar = st.progress(0) | |
status_text = st.empty() | |
def update_progress(progress, status): | |
if progress >= 0: | |
progress_bar.progress(progress) | |
status_text.text(status) | |
downloaded_file, error = download_with_retry(video_url, update_progress) | |
if downloaded_file and os.path.exists(downloaded_file): | |
with open(downloaded_file, 'rb') as file: | |
st.download_button( | |
label="โฌ๏ธ Download Video", | |
data=file, | |
file_name=os.path.basename(downloaded_file), | |
mime="video/mp4" | |
) | |
st.success("โ Download completed successfully!") | |
else: | |
st.error(f"โ {error}") | |
else: | |
st.warning("โ ๏ธ Please enter a valid YouTube URL.") | |
with col2: | |
render_settings_panel() | |
def render_settings_panel(): | |
with st.expander("โ๏ธ Settings & Information"): | |
st.markdown("**Authentication Status:**") | |
if os.path.exists(Config.COOKIES_FILE): | |
st.success("โ Cookie authentication active") | |
if st.button("Remove Cookie File"): | |
try: | |
os.remove(Config.COOKIES_FILE) | |
st.rerun() | |
except Exception as e: | |
st.error(f"Failed to remove cookie file: {str(e)}") | |
else: | |
st.warning(""" | |
โ ๏ธ No cookie authentication configured | |
To enable cookie authentication: | |
1. Install a browser extension to export cookies | |
2. Export cookies from YouTube (while logged in) | |
3. Save as 'youtube.com_cookies.txt' in the app directory | |
""") | |
# Cookie file uploader | |
uploaded_file = st.file_uploader("Upload Cookie File", type=['txt']) | |
if uploaded_file is not None: | |
try: | |
with open(Config.COOKIES_FILE, 'wb') as f: | |
f.write(uploaded_file.getvalue()) | |
st.success("โ Cookie file uploaded successfully!") | |
st.rerun() | |
except Exception as e: | |
st.error(f"Failed to save cookie file: {str(e)}") | |
def render_help_section(): | |
with st.expander("โ Help & Troubleshooting"): | |
st.markdown(""" | |
**Common Issues & Solutions:** | |
1. **Bot Detection Issues:** | |
- The app now implements multiple retry strategies | |
- Uses random delays between attempts | |
- Rotates User-Agents automatically | |
- Uses cookie authentication when available | |
2. **Download Problems:** | |
- Check if the video is public and available | |
- Verify your internet connection | |
- Try uploading a fresh cookie file | |
- Clear browser cache and try again | |
3. **Quality Settings:** | |
- Automatically selects best available quality | |
- Prioritizes MP4 format when available | |
- Handles premium content with proper authentication | |
**Need More Help?** | |
- Make sure you're using an up-to-date browser | |
- Check if the video is available in your region | |
- Consider using a VPN if region-blocked | |
- Ensure your cookie file is recent and valid | |
""") | |
# Main App | |
def main(): | |
render_main_ui() | |
render_help_section() | |
if __name__ == "__main__": | |
main() |