File size: 3,013 Bytes
a90b1ae b35c517 a90b1ae b35c517 a90b1ae b35c517 a90b1ae b35c517 a90b1ae ca4952f a90b1ae b35c517 a90b1ae ca4952f a90b1ae b35c517 a90b1ae |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
from fastapi import FastAPI, HTTPException, Query, BackgroundTasks
from pydantic import BaseModel
import subprocess
import uuid
import os
import json
import shutil
app = FastAPI()
tasks = {}
class DownloadRequest(BaseModel):
url: str
format_id: str # yt-dlp format code
output_name: str = None
convert_to: str = None # e.g. mp3 or mp4
@app.get("/info")
async def get_video_info(url: str = Query(...)):
try:
cmd = [
"yt-dlp",
"--no-warnings",
"--skip-download",
"--print-json",
url
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(result.stderr)
data = json.loads(result.stdout)
return {
"title": data.get("title"),
"thumbnail": data.get("thumbnail"),
"formats": [
{"id": f["format_id"], "ext": f["ext"], "note": f.get("format_note"), "filesize": f.get("filesize")}
for f in data.get("formats", [])
if f.get("vcodec") != "none" or f.get("acodec") != "none"
]
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error getting info: {e}")
@app.post("/download")
async def download_media(request: DownloadRequest, background_tasks: BackgroundTasks):
task_id = str(uuid.uuid4())
tasks[task_id] = {"status": "queued"}
def _do_download():
try:
output_file = f"{request.output_name or 'video'}_{task_id}"
if request.convert_to:
output_file += f".{request.convert_to}"
else:
output_file += ".%(ext)s"
cmd = [
"yt-dlp",
"-f", request.format_id,
"-o", f"/tmp/{output_file}",
request.url
]
if request.convert_to:
cmd += ["--recode-video", request.convert_to]
tasks[task_id]["status"] = "downloading"
subprocess.run(cmd, capture_output=True, text=True)
tasks[task_id]["status"] = "completed"
tasks[task_id]["file"] = f"/tmp/{output_file}"
except Exception as e:
tasks[task_id]["status"] = "error"
tasks[task_id]["error"] = str(e)
background_tasks.add_task(_do_download)
return {"task_id": task_id}
@app.get("/progress/{task_id}")
def check_progress(task_id: str):
if task_id not in tasks:
raise HTTPException(status_code=404, detail="Task ID not found")
return tasks[task_id]
@app.get("/cancel/{task_id}")
def cancel_task(task_id: str):
# Basic cancellation support stub (real cancellation needs async task mgmt)
if task_id in tasks and tasks[task_id]["status"] not in ["completed", "error"]:
tasks[task_id]["status"] = "cancelled"
return {"detail": "Task cancelled"}
raise HTTPException(status_code=404, detail="Task not found or already done") |