import os import uuid from fastapi import FastAPI, Request, Form from fastapi.templating import Jinja2Templates from fastapi.responses import HTMLResponse, FileResponse from fastapi.concurrency import run_in_threadpool import yt_dlp app = FastAPI() templates = Jinja2Templates(directory="templates") # Use /tmp/downloads which is writable in most environments like Hugging Face Spaces DOWNLOAD_FOLDER = "/tmp/downloads" os.makedirs(DOWNLOAD_FOLDER, exist_ok=True) def download_video(url: str, output_path: str): ydl_opts = { 'outtmpl': output_path, # File output template (unique_id.ext) 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best', # Download best quality 'merge_output_format': 'mp4', # Merge into MP4 'quiet': True, 'no_warnings': True, } with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download([url]) @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse("index.html", {"request": request}) @app.post("/download", response_class=HTMLResponse) async def download(request: Request, video_url: str = Form(...)): unique_id = uuid.uuid4().hex # The file will be saved as . output_template = os.path.join(DOWNLOAD_FOLDER, f"{unique_id}.%(ext)s") try: # Offload the blocking download function to a thread await run_in_threadpool(download_video, video_url, output_template) downloaded_file = None # Locate the downloaded file for file in os.listdir(DOWNLOAD_FOLDER): if file.startswith(unique_id): downloaded_file = file break if not downloaded_file: raise Exception("Failed to download video.") download_link = f"/download_file/{downloaded_file}" return templates.TemplateResponse("result.html", {"request": request, "download_link": download_link}) except Exception as e: return templates.TemplateResponse("index.html", {"request": request, "error": str(e)}) @app.get("/download_file/{filename}", response_class=FileResponse) async def get_file(filename: str): file_path = os.path.join(DOWNLOAD_FOLDER, filename) if os.path.exists(file_path): return FileResponse(file_path, media_type='video/mp4', filename=filename) return HTMLResponse("File not found", status_code=404)