// 端到端跑一次「合成完整视频」:提交 → 轮询进度 → 拿成片地址(验证 ffmpeg 真拼出来了) const API = process.env.API || "http://127.0.0.1:8010"; const PROJECT = process.argv[2]; if (!PROJECT) throw new Error("用法: node _merge-e2e.mjs "); const login = await (await fetch(`${API}/api/auth/login/`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: "airshelf", password: "Restraint2026" }) })).json(); const auth = { Authorization: `Token ${login.token}`, "Content-Type": "application/json" }; const t0 = Date.now(); const submit = await fetch(`${API}/api/projects/${PROJECT}/submit-export/`, { method: "POST", headers: auth }); console.log("submit:", submit.status, JSON.stringify(await submit.json())); // 顺手验一下防重复:立刻再提一次,应该拿到同一条任务 const again = await (await fetch(`${API}/api/projects/${PROJECT}/submit-export/`, { method: "POST", headers: auth })).json(); console.log("再提一次(应复用同一任务):", again.id, again.status); for (let i = 0; i < 200; i += 1) { await new Promise((r) => setTimeout(r, 2000)); const res = await (await fetch(`${API}/api/projects/${PROJECT}/poll-export/`, { method: "POST", headers: auth })).json(); const secs = ((Date.now() - t0) / 1000).toFixed(0); console.log(` ${secs}s · ${res.status} · ${res.progress}%`, res.error_message || ""); if (res.status === "succeeded") { console.log("成片:", res.output_url); const head = await fetch(res.output_url, { method: "HEAD" }); console.log("成片可访问:", head.status, head.headers.get("content-type"), head.headers.get("content-length"), "bytes"); const detail = await (await fetch(`${API}/api/projects/${PROJECT}/`, { headers: auth })).json(); console.log("详情 final_video_url:", detail.final_video_url ? "有" : "空", "· current_stage:", detail.current_stage); break; } if (res.status === "failed") { console.log("失败:", res.error_message); break; } }