File size: 2,629 Bytes
3584130 e3c6be7 e17c1c3 | 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 | import asyncio
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from playwright.async_api import async_playwright
app = FastAPI(title="SaveFrom Extractor API")
class DownloadRequest(BaseModel):
url: str
@app.get("/")
def root():
return {"status": "ok"}
@app.post("/download")
async def extract(req: DownloadRequest):
target = f"https://en.savefrom.net/1/{req.url}"
try:
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=True,
args=[
"--no-sandbox",
"--disable-dev-shm-usage",
"--disable-blink-features=AutomationControlled",
],
)
context = await browser.new_context(
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"
),
viewport={"width": 1280, "height": 720},
)
page = await context.new_page()
await page.goto(target, wait_until="networkidle", timeout=60_000)
# Give SaveFrom time to populate links
await page.wait_for_timeout(4000)
links = await page.evaluate("""
() => {
const results = [];
document.querySelectorAll("a").forEach(a => {
const href = a.href || "";
if (href.includes(".mp4") || href.includes(".mp3")) {
results.push({
url: href,
text: a.innerText || null
});
}
});
return results;
}
""")
await browser.close()
if not links:
raise HTTPException(
status_code=404,
detail="No downloadable links found"
)
return {
"source": "neon dl",
"original_url": req.url,
"count": len(links),
"links": links
}
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Extractor error: {str(e)}"
)
#if __name__ == "__main__":
# uvicorn.run(
# "app:app",
# host="0.0.0.0",
# port=int(os.environ.get("PORT", 7860)),
# log_level="info"
# ) |