| import os |
| import uuid |
| import logging |
| from pathlib import Path |
| import subprocess |
|
|
| import gradio as gr |
| import yt_dlp |
|
|
| |
| logging.basicConfig( |
| level=logging.INFO, |
| format="%(asctime)s - %(levelname)s - %(message)s" |
| ) |
|
|
| logging.getLogger("urllib3").setLevel(logging.WARNING) |
| logging.getLogger("httpx").setLevel(logging.WARNING) |
|
|
| logger = logging.getLogger(__name__) |
|
|
| |
| if "YOUTUBE_COOKIES" in os.environ: |
| with open("/tmp/cookies.txt", "w", encoding="utf-8") as f: |
| f.write(os.environ["YOUTUBE_COOKIES"]) |
|
|
|
|
| def download_media(url: str, format_choice: str, progress=gr.Progress()): |
| if not url: |
| raise gr.Error("Please enter a valid YouTube URL.") |
|
|
| logger.info(f"New download request. URL: {url}, Format: {format_choice}") |
|
|
| |
| session_id = str(uuid.uuid4()) |
| out_dir = Path("/tmp/downloads") / session_id |
| out_dir.mkdir(parents=True, exist_ok=True) |
|
|
| logger.info(f"Created temporary directory: {out_dir}") |
|
|
| def progress_hook(d): |
| if d["status"] == "downloading": |
| total = d.get("total_bytes") or d.get("total_bytes_estimate", 0) |
| downloaded = d.get("downloaded_bytes", 0) |
|
|
| if total > 0: |
| progress(downloaded / total, desc="Downloading...") |
|
|
| elif d["status"] == "finished": |
| progress(1.0, desc="Processing with ffmpeg...") |
|
|
| try: |
| |
| info_opts = { |
| "quiet": False, |
| "verbose": True, |
| "no_warnings": False, |
| "cookiefile": "/tmp/cookies.txt" |
| if os.path.exists("/tmp/cookies.txt") |
| else None, |
| "extractor_retries": 10, |
| "skip_download": True, |
| "noplaylist": True, |
| "extractor_args": { |
| "youtube": { |
| "player_skip": ["webpage", "configs"], |
| } |
| }, |
| } |
|
|
| with yt_dlp.YoutubeDL(info_opts) as ydl: |
| logger.info("Extracting video information...") |
| info_dict = ydl.extract_info( |
| url, |
| download=False, |
| process=False |
| ) |
|
|
| formats = info_dict.get("formats", []) |
|
|
| logger.info("----- AVAILABLE FORMATS -----") |
|
|
| for f in formats: |
| logger.info( |
| f"ID: {f.get('format_id')} | " |
| f"EXT: {f.get('ext')} | " |
| f"RES: {f.get('resolution')} | " |
| f"VCODEC: {f.get('vcodec')} | " |
| f"ACODEC: {f.get('acodec')}" |
| ) |
|
|
| logger.info("-----------------------------") |
|
|
| |
| download_opts = { |
| "outtmpl": str(out_dir / "%(title)s.%(ext)s"), |
| "progress_hooks": [progress_hook], |
| "quiet": True, |
| "no_warnings": True, |
| "cookiefile": "/tmp/cookies.txt" |
| if os.path.exists("/tmp/cookies.txt") |
| else None, |
| "extractor_retries": 5, |
| "extractor_args": { |
| "youtube": { |
| "player_skip": ["webpage", "configs"], |
| } |
| }, |
| } |
|
|
| |
| if format_choice == "Audio (MP3)": |
| download_opts.update({ |
| "format": "bestaudio/best", |
| "postprocessors": [{ |
| "key": "FFmpegExtractAudio", |
| "preferredcodec": "mp3", |
| "preferredquality": "192", |
| }], |
| }) |
|
|
| |
| else: |
| download_opts.update({ |
| "format": "bestvideo+bestaudio/best", |
| "merge_output_format": "mp4", |
| }) |
|
|
| logger.info( |
| f"Downloading using selector: {download_opts['format']}" |
| ) |
|
|
| with yt_dlp.YoutubeDL(download_opts) as ydl: |
| ydl.download([url]) |
|
|
| logger.info("Download completed successfully.") |
|
|
| downloaded_files = list(out_dir.glob("*")) |
|
|
| if downloaded_files: |
| logger.info(f"Downloaded file: {downloaded_files[0]}") |
| return str(downloaded_files[0]) |
|
|
| raise gr.Error("Download failed: No file generated.") |
|
|
| except Exception as e: |
| logger.error( |
| f"yt-dlp exception: {str(e)}", |
| exc_info=True |
| ) |
|
|
| raise gr.Error( |
| f"Download failed.\n\nError:\n{str(e)}" |
| ) |
|
|
|
|
| |
| custom_theme = gr.themes.Monochrome( |
| font=[ |
| gr.themes.GoogleFont("Inter"), |
| "ui-sans-serif", |
| "system-ui", |
| "sans-serif", |
| ] |
| ) |
|
|
| |
| with gr.Blocks( |
| title="YouTube Downloader", |
| theme=custom_theme |
| ) as app: |
|
|
| gr.Markdown("# YouTube Cloud Downloader") |
|
|
| gr.Markdown( |
| "Download YouTube videos or audio directly." |
| ) |
|
|
| url_input = gr.Textbox( |
| label="YouTube URL", |
| placeholder="https://www.youtube.com/watch?v=..." |
| ) |
|
|
| format_input = gr.Radio( |
| choices=[ |
| "Video (MP4)", |
| "Audio (MP3)" |
| ], |
| label="Format", |
| value="Video (MP4)" |
| ) |
|
|
| download_btn = gr.Button( |
| "Download", |
| variant="primary", |
| size="lg" |
| ) |
|
|
| output_file = gr.File( |
| label="Downloaded File" |
| ) |
|
|
| download_btn.click( |
| fn=download_media, |
| inputs=[url_input, format_input], |
| outputs=output_file |
| ) |
|
|
| |
| if __name__ == "__main__": |
| app.launch( |
| server_name="0.0.0.0", |
| server_port=7860 |
| ) |