Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -33,10 +33,9 @@ WORKFLOW_FILE = os.getenv("WORKFLOW_FILE", "video-download.yml")
|
|
| 33 |
# e.g. https://my-api.hf.space or https://xxxxx.ngrok.io
|
| 34 |
PUBLIC_URL = os.getenv("PUBLIC_URL", "https://your-api-public-url.com")
|
| 35 |
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
)
|
| 40 |
|
| 41 |
VIDEOS_DIR = Path("videos")
|
| 42 |
VIDEOS_DIR.mkdir(exist_ok=True)
|
|
@@ -47,9 +46,11 @@ jobs: dict[str, dict] = {}
|
|
| 47 |
|
| 48 |
# ─── App ───────────────────────────────────────────────────────────────────────
|
| 49 |
app = FastAPI(
|
| 50 |
-
title="
|
| 51 |
description="Bridges client ↔ n8n/GitHub Action video pipeline",
|
| 52 |
version="1.0.0",
|
|
|
|
|
|
|
| 53 |
)
|
| 54 |
|
| 55 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
|
|
@@ -80,8 +81,16 @@ async def download_shorts(body: DownloadRequest):
|
|
| 80 |
@app.post("/download", summary="Start a video download job")
|
| 81 |
async def start_download(body: DownloadRequest):
|
| 82 |
"""
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
"""
|
| 86 |
job_id = str(uuid.uuid4())
|
| 87 |
|
|
@@ -93,29 +102,39 @@ async def start_download(body: DownloadRequest):
|
|
| 93 |
"run_id": None,
|
| 94 |
"error": None,
|
| 95 |
"created_at": time.time(),
|
|
|
|
| 96 |
}
|
| 97 |
|
| 98 |
-
#
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
jobs[job_id]["status"] = "processing"
|
| 111 |
-
log.info(f"[{job_id}] job triggered → n8n responded {r.status_code}")
|
| 112 |
-
except Exception as exc:
|
| 113 |
-
jobs[job_id]["status"] = "failed"
|
| 114 |
-
jobs[job_id]["error"] = str(exc)
|
| 115 |
-
log.error(f"[{job_id}] failed to trigger n8n: {exc}")
|
| 116 |
-
raise HTTPException(status_code=502, detail=f"Could not trigger pipeline: {exc}")
|
| 117 |
|
| 118 |
-
return {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
|
| 120 |
|
| 121 |
# ══════════════════════════════════════════════════════════════════════════════
|
|
|
|
| 33 |
# e.g. https://my-api.hf.space or https://xxxxx.ngrok.io
|
| 34 |
PUBLIC_URL = os.getenv("PUBLIC_URL", "https://your-api-public-url.com")
|
| 35 |
|
| 36 |
+
# اختياري - لو موجود الـ API هو اللي يشغل n8n
|
| 37 |
+
# لو None، n8n هو اللي يبعت callback للـ API
|
| 38 |
+
N8N_TRIGGER_URL = os.getenv("N8N_TRIGGER_URL", None)
|
|
|
|
| 39 |
|
| 40 |
VIDEOS_DIR = Path("videos")
|
| 41 |
VIDEOS_DIR.mkdir(exist_ok=True)
|
|
|
|
| 46 |
|
| 47 |
# ─── App ───────────────────────────────────────────────────────────────────────
|
| 48 |
app = FastAPI(
|
| 49 |
+
title="EGDownloader API",
|
| 50 |
description="Bridges client ↔ n8n/GitHub Action video pipeline",
|
| 51 |
version="1.0.0",
|
| 52 |
+
docs_url="/",
|
| 53 |
+
redoc_url="/redoc",
|
| 54 |
)
|
| 55 |
|
| 56 |
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
|
|
|
|
| 81 |
@app.post("/download", summary="Start a video download job")
|
| 82 |
async def start_download(body: DownloadRequest):
|
| 83 |
"""
|
| 84 |
+
طريقتين للشغل:
|
| 85 |
+
|
| 86 |
+
1) Push mode (الـ default - اللي عندك دلوقتي):
|
| 87 |
+
N8N_TRIGGER_URL = None
|
| 88 |
+
n8n هو اللي يشغل GitHub Action وبعدين يبعت callback على /n8n/callback/{job_id}
|
| 89 |
+
الـ client بس يعمل polling على /status/{job_id}
|
| 90 |
+
|
| 91 |
+
2) Trigger mode:
|
| 92 |
+
N8N_TRIGGER_URL = "https://..."
|
| 93 |
+
الـ API هو اللي يبعت trigger لـ n8n، وn8n يرد بـ callback
|
| 94 |
"""
|
| 95 |
job_id = str(uuid.uuid4())
|
| 96 |
|
|
|
|
| 102 |
"run_id": None,
|
| 103 |
"error": None,
|
| 104 |
"created_at": time.time(),
|
| 105 |
+
"mode": "trigger" if N8N_TRIGGER_URL else "push",
|
| 106 |
}
|
| 107 |
|
| 108 |
+
# ── Trigger mode: الـ API يشغل n8n ────────────────────────────────────────
|
| 109 |
+
if N8N_TRIGGER_URL:
|
| 110 |
+
payload = {
|
| 111 |
+
"url": body.url,
|
| 112 |
+
"cookies_txt": body.cookies_txt or "",
|
| 113 |
+
"n8n_webhook": f"{PUBLIC_URL}/n8n/callback/{job_id}",
|
| 114 |
+
}
|
| 115 |
+
try:
|
| 116 |
+
async with httpx.AsyncClient(timeout=15) as client:
|
| 117 |
+
r = await client.post(N8N_TRIGGER_URL, json=payload)
|
| 118 |
+
r.raise_for_status()
|
| 119 |
+
jobs[job_id]["status"] = "processing"
|
| 120 |
+
log.info(f"[{job_id}] triggered n8n → {r.status_code}")
|
| 121 |
+
except Exception as exc:
|
| 122 |
+
jobs[job_id]["status"] = "failed"
|
| 123 |
+
jobs[job_id]["error"] = str(exc)
|
| 124 |
+
log.error(f"[{job_id}] failed to trigger n8n: {exc}")
|
| 125 |
+
raise HTTPException(status_code=502, detail=f"Could not trigger pipeline: {exc}")
|
| 126 |
|
| 127 |
+
# ── Push mode: n8n هو اللي هيبعت callback لما يخلص ───────────────────────
|
| 128 |
+
else:
|
| 129 |
+
jobs[job_id]["status"] = "pending"
|
| 130 |
+
log.info(f"[{job_id}] job created (push mode) - waiting for n8n callback")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
+
return {
|
| 133 |
+
"job_id": job_id,
|
| 134 |
+
"status": jobs[job_id]["status"],
|
| 135 |
+
"mode": jobs[job_id]["mode"],
|
| 136 |
+
"callback_url": f"{PUBLIC_URL}/n8n/callback/{job_id}",
|
| 137 |
+
}
|
| 138 |
|
| 139 |
|
| 140 |
# ══════════════════════════════════════════════════════════════════════════════
|