# 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: @staticmethod def create_cookie_jar(): return cookielib.MozillaCookieJar(Config.COOKIES_FILE) @staticmethod def get_random_headers(): ua = UserAgent() headers = random.choice(Config.HEADERS_POOL).copy() headers['User-Agent'] = ua.random return headers @staticmethod 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()