jpjp9292's picture
Update app.py
cb64250 verified
raw
history blame
20.7 kB
# 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()