@bylqwjc/media-editor-server 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +5 -5
  2. package/core/dist/browser.cjs +1 -1
  3. package/core/dist/browser.js +1 -3
  4. package/core/dist/chunk-MGKYVYOH.js +1 -1
  5. package/core/dist/chunk-USY6UDGL.js +1 -1
  6. package/core/dist/chunk-XCBM7P7N.js +1 -1
  7. package/core/dist/engine.cjs +1 -1
  8. package/core/dist/engine.js +1 -1
  9. package/core/dist/filerobot.cjs +1 -1
  10. package/core/dist/filerobot.js +1 -1
  11. package/core/dist/index.cjs +1 -1
  12. package/core/dist/index.js +1 -1
  13. package/core/package.json +1 -1
  14. package/core/zod/index.cjs +1 -1
  15. package/core/zod/index.js +1 -1
  16. package/core/zod/v3/ZodError.cjs +1 -1
  17. package/core/zod/v3/ZodError.js +1 -1
  18. package/core/zod/v3/errors.cjs +1 -1
  19. package/core/zod/v3/errors.js +1 -1
  20. package/core/zod/v3/external.cjs +1 -1
  21. package/core/zod/v3/external.js +1 -1
  22. package/core/zod/v3/helpers/enumUtil.cjs +1 -1
  23. package/core/zod/v3/helpers/errorUtil.cjs +1 -1
  24. package/core/zod/v3/helpers/errorUtil.js +1 -1
  25. package/core/zod/v3/helpers/parseUtil.cjs +1 -1
  26. package/core/zod/v3/helpers/parseUtil.js +1 -1
  27. package/core/zod/v3/helpers/partialUtil.cjs +1 -1
  28. package/core/zod/v3/helpers/typeAliases.cjs +1 -1
  29. package/core/zod/v3/helpers/util.cjs +1 -1
  30. package/core/zod/v3/helpers/util.js +1 -1
  31. package/core/zod/v3/index.cjs +1 -1
  32. package/core/zod/v3/index.js +1 -1
  33. package/core/zod/v3/locales/en.cjs +1 -1
  34. package/core/zod/v3/locales/en.js +1 -1
  35. package/core/zod/v3/standard-schema.cjs +1 -1
  36. package/core/zod/v3/types.cjs +1 -1
  37. package/core/zod/v3/types.js +1 -1
  38. package/dist/adapters/express.cjs +1 -1
  39. package/dist/adapters/express.js +1 -1
  40. package/dist/adapters/web.cjs +1 -1
  41. package/dist/adapters/web.js +1 -1
  42. package/dist/index.cjs +1 -4
  43. package/dist/index.js +1 -4
  44. package/express/express/index.cjs +1 -0
  45. package/express/express/index.d.ts +1 -0
  46. package/express/express/index.js +1 -0
  47. package/express/index.cjs +1 -1
  48. package/express/index.js +1 -1
  49. package/package.json +1 -1
  50. package/web/index.cjs +1 -1
  51. package/web/index.js +1 -1
  52. package/web/web/index.cjs +1 -0
  53. package/web/web/index.d.ts +1 -0
  54. package/web/web/index.js +1 -0
@@ -1 +1 @@
1
- "use strict";var c=Object.defineProperty,w=Object.getOwnPropertyDescriptor,B=Object.getOwnPropertyNames,h=Object.prototype.hasOwnProperty,v=(t,r)=>{for(var e in r)c(t,e,{get:r[e],enumerable:!0})},D=(t,r,e,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let a of B(r))!h.call(t,a)&&a!==e&&c(t,a,{get:()=>r[a],enumerable:!(o=w(r,a))||o.enumerable});return t},C=t=>D(c({},"__esModule",{value:!0}),t),g={};v(g,{toWebPosterHandler:()=>O,toWebVideoHandler:()=>E}),module.exports=C(g);var m=16;function f(t){return typeof t=="object"&&t!==null&&typeof t.type=="string"&&typeof t.arrayBuffer=="function"}async function y(t){return{type:t.type,bytes:Buffer.from(await t.arrayBuffer())}}function s(t){return t.ok?new Response(new Uint8Array(t.bytes),{status:200,headers:{"Content-Type":t.contentType,"Content-Disposition":`attachment; filename="${t.filename}"`,"Cache-Control":"no-store"}}):new Response(JSON.stringify({error:t.error,message:t.message}),{status:t.status,headers:{"Content-Type":"application/json"}})}function E(t){return async r=>{let e;try{e=await r.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const o=[];for(let n=0;n<m;n++){const u=e.get(`video_${n}`);if(!f(u))break;o.push(await y(u))}const a=[];for(let n=0;n<m;n++){const u=e.get(`audio_${n}`);if(!f(u))break;a.push(await y(u))}const p=e.get("editState"),l=e.get("overlay"),i=f(l)?l:void 0,d=i?Buffer.from(await i.arrayBuffer()):void 0;if(i&&i.type!=="image/png")return s({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});const b={videos:o,audios:a,overlay:d,editStateRaw:typeof p=="string"?p:""};return s(await t.handle(b))}}function O(t){return async r=>{let e;try{e=await r.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const o=e.get("file"),a=e.get("time");return!f(o)||typeof a!="string"?s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"}):s(await t.handle(await y(o),Number(a)))}}
1
+ "use strict";var c=Object.defineProperty,w=Object.getOwnPropertyDescriptor,B=Object.getOwnPropertyNames,h=Object.prototype.hasOwnProperty,v=(e,t)=>{for(var r in t)c(e,r,{get:t[r],enumerable:!0})},D=(e,t,r,a)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let o of B(t))!h.call(e,o)&&o!==r&&c(e,o,{get:()=>t[o],enumerable:!(a=w(t,o))||a.enumerable});return e},C=e=>D(c({},"__esModule",{value:!0}),e),g={};v(g,{toWebPosterHandler:()=>O,toWebVideoHandler:()=>E}),module.exports=C(g);var m=16;function f(e){return"object"==typeof e&&null!==e&&"string"==typeof e.type&&"function"==typeof e.arrayBuffer}async function y(e){return{type:e.type,bytes:Buffer.from(await e.arrayBuffer())}}function s(e){return e.ok?new Response(new Uint8Array(e.bytes),{status:200,headers:{"Content-Type":e.contentType,"Content-Disposition":`attachment; filename="${e.filename}"`,"Cache-Control":"no-store"}}):new Response(JSON.stringify({error:e.error,message:e.message}),{status:e.status,headers:{"Content-Type":"application/json"}})}function E(e){return async t=>{let r;try{r=await t.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"请求体解析失败"})}const a=[];for(let e=0;e<m;e++){const t=r.get(`video_${e}`);if(!f(t))break;a.push(await y(t))}const o=[];for(let e=0;e<m;e++){const t=r.get(`audio_${e}`);if(!f(t))break;o.push(await y(t))}const n=r.get("editState"),i=r.get("overlay"),u=f(i)?i:void 0,c=u?Buffer.from(await u.arrayBuffer()):void 0;if(u&&"image/png"!==u.type)return s({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay 必须是 PNG"});const p={videos:a,audios:o,overlay:c,editStateRaw:"string"==typeof n?n:""};return s(await e.handle(p))}}function O(e){return async t=>{let r;try{r=await t.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"请求体解析失败"})}const a=r.get("file"),o=r.get("time");return f(a)&&"string"==typeof o?s(await e.handle(await y(a),Number(o))):s({ok:!1,status:400,error:"BAD_REQUEST",message:"缺少 file time"})}}
@@ -1 +1 @@
1
- var g=16;function s(e){return typeof e=="object"&&e!==null&&typeof e.type=="string"&&typeof e.arrayBuffer=="function"}async function p(e){return{type:e.type,bytes:Buffer.from(await e.arrayBuffer())}}function o(e){return e.ok?new Response(new Uint8Array(e.bytes),{status:200,headers:{"Content-Type":e.contentType,"Content-Disposition":`attachment; filename="${e.filename}"`,"Cache-Control":"no-store"}}):new Response(JSON.stringify({error:e.error,message:e.message}),{status:e.status,headers:{"Content-Type":"application/json"}})}function C(e){return async y=>{let t;try{t=await y.formData()}catch{return o({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const u=[];for(let r=0;r<g;r++){const a=t.get(`video_${r}`);if(!s(a))break;u.push(await p(a))}const n=[];for(let r=0;r<g;r++){const a=t.get(`audio_${r}`);if(!s(a))break;n.push(await p(a))}const c=t.get("editState"),l=t.get("overlay"),m=t.get("videoCover"),i=s(l)?l:void 0,f=s(m)?m:void 0,B=i?Buffer.from(await i.arrayBuffer()):void 0,v=f?Buffer.from(await f.arrayBuffer()):void 0,d=[];for(let r=0;r<g;r++){const a=t.get(`textOverlay_${r}`);if(!s(a))break;if(a.type!=="image/png")return o({ok:!1,status:415,error:"BAD_OVERLAY",message:"textOverlay \u5FC5\u987B\u662F PNG"});d.push(Buffer.from(await a.arrayBuffer()))}if(i&&i.type!=="image/png")return o({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});if(f&&!/^image\/(?:png|jpe?g)$/.test(f.type))return o({ok:!1,status:415,error:"BAD_COVER",message:"videoCover \u5FC5\u987B\u662F PNG \u6216 JPG"});const w={videos:u,audios:n,overlay:B,videoCover:v,textOverlays:d,editStateRaw:typeof c=="string"?c:""};return o(await e.handle(w))}}function F(e){return async y=>{let t;try{t=await y.formData()}catch{return o({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const u=t.get("file"),n=t.get("time");return!s(u)||typeof n!="string"?o({ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"}):o(await e.handle(await p(u),Number(n)))}}export{F as toWebPosterHandler,C as toWebVideoHandler};
1
+ function e(e){return"object"==typeof e&&null!==e&&"string"==typeof e.type&&"function"==typeof e.arrayBuffer}async function t(e){return{type:e.type,bytes:Buffer.from(await e.arrayBuffer())}}function r(e){return e.ok?new Response(new Uint8Array(e.bytes),{status:200,headers:{"Content-Type":e.contentType,"Content-Disposition":`attachment; filename="${e.filename}"`,"Cache-Control":"no-store"}}):new Response(JSON.stringify({error:e.error,message:e.message}),{status:e.status,headers:{"Content-Type":"application/json"}})}function a(a){return async o=>{let s;try{s=await o.formData()}catch{return r({ok:!1,status:400,error:"BAD_REQUEST",message:"请求体解析失败"})}const n=[];for(let r=0;r<16;r++){const a=s.get(`video_${r}`);if(!e(a))break;n.push(await t(a))}const i=[];for(let r=0;r<16;r++){const a=s.get(`audio_${r}`);if(!e(a))break;i.push(await t(a))}const f=s.get("editState"),u=s.get("overlay"),y=s.get("videoCover"),g=e(u)?u:void 0,p=e(y)?y:void 0,c=g?Buffer.from(await g.arrayBuffer()):void 0,l=p?Buffer.from(await p.arrayBuffer()):void 0,m=[];for(let t=0;t<16;t++){const a=s.get(`textOverlay_${t}`);if(!e(a))break;if("image/png"!==a.type)return r({ok:!1,status:415,error:"BAD_OVERLAY",message:"textOverlay 必须是 PNG"});m.push(Buffer.from(await a.arrayBuffer()))}if(g&&"image/png"!==g.type)return r({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay 必须是 PNG"});if(p&&!/^image\/(?:png|jpe?g)$/.test(p.type))return r({ok:!1,status:415,error:"BAD_COVER",message:"videoCover 必须是 PNG JPG"});const d={videos:n,audios:i,overlay:c,videoCover:l,textOverlays:m,editStateRaw:"string"==typeof f?f:""};return r(await a.handle(d))}}function o(a){return async o=>{let s;try{s=await o.formData()}catch{return r({ok:!1,status:400,error:"BAD_REQUEST",message:"请求体解析失败"})}const n=s.get("file"),i=s.get("time");return e(n)&&"string"==typeof i?r(await a.handle(await t(n),Number(i))):r({ok:!1,status:400,error:"BAD_REQUEST",message:"缺少 file time"})}}export{o as toWebPosterHandler,a as toWebVideoHandler};
package/dist/index.cjs CHANGED
@@ -1,4 +1 @@
1
- "use strict";var z=Object.create;var V=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var W=(e,t,u,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of U(t))!Q.call(e,r)&&r!==u&&V(e,r,{get:()=>t[r],enumerable:!(n=K(t,r))||n.enumerable});return e};var X=(e,t,u)=>(u=e!=null?z(J(e)):{},W(t||!e||!e.__esModule?V(u,"default",{value:e,enumerable:!0}):u,e));var Z=Object.create,M=Object.defineProperty,ee=Object.getOwnPropertyDescriptor,te=Object.getOwnPropertyNames,ue=Object.getPrototypeOf,re=Object.prototype.hasOwnProperty,oe=(e,t,u,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of te(t))!re.call(e,r)&&r!==u&&M(e,r,{get:()=>t[r],enumerable:!(n=ee(t,r))||n.enumerable});return e},ke=(e,t,u)=>(u=e!=null?Z(ue(e)):{},oe(t||!e||!e.__esModule?M(u,"default",{value:e,enumerable:!0}):u,e)),ne=Object.create,R=Object.defineProperty,ie=Object.getOwnPropertyDescriptor,ae=Object.getOwnPropertyNames,se=Object.getPrototypeOf,ce=Object.prototype.hasOwnProperty,le=(e,t,u,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ae(t))!ce.call(e,r)&&r!==u&&R(e,r,{get:()=>t[r],enumerable:!(n=ie(t,r))||n.enumerable});return e},Ne=(e,t,u)=>(u=e!=null?ne(se(e)):{},le(t||!e||!e.__esModule?R(u,"default",{value:e,enumerable:!0}):u,e)),pe=Object.create,I=Object.defineProperty,me=Object.getOwnPropertyDescriptor,fe=Object.getOwnPropertyNames,de=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty,ye=(e,t,u,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of fe(t))!ge.call(e,r)&&r!==u&&I(e,r,{get:()=>t[r],enumerable:!(n=me(t,r))||n.enumerable});return e},qe=(e,t,u)=>(u=e!=null?pe(de(e)):{},ye(t||!e||!e.__esModule?I(u,"default",{value:e,enumerable:!0}):u,e)),Fe=Object.create,D=Object.defineProperty,we=Object.getOwnPropertyDescriptor,ve=Object.getOwnPropertyNames,Ae=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty,Ee=(e,t)=>{for(var u in t)D(e,u,{get:t[u],enumerable:!0})},L=(e,t,u,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ve(t))!he.call(e,r)&&r!==u&&D(e,r,{get:()=>t[r],enumerable:!(n=we(t,r))||n.enumerable});return e},be=(e,t,u)=>(u=e!=null?Fe(Ae(e)):{},L(t||!e||!e.__esModule?D(u,"default",{value:e,enumerable:!0}):u,e)),Ce=e=>L(D({},"__esModule",{value:!0}),e),k={};Ee(k,{DEFAULT_LIMITS:()=>Y,composeVideo:()=>Pe,createPosterHandler:()=>Ie,createVideoExportHandler:()=>Re,extractAudio:()=>xe,probeHasAudio:()=>P,probeVideoDuration:()=>q,runVideoEdit:()=>$}),module.exports=Ce(k);var Oe=require("../core/dist/index.cjs"),N=require("../core/dist/index.cjs"),T=be(require("ffmpeg-static"),1),_=require("child_process"),d=require("fs/promises"),Be=require("fs"),De=require("os"),m=require("path"),_e={};async function je(){const e=[];T.default&&typeof T.default=="string"&&e.push(T.default);try{const{createRequire:t}=await import("module"),u=t(_e.url).resolve("ffmpeg-static/package.json"),n=u.substring(0,u.lastIndexOf("/"));e.push((0,m.join)(n,"ffmpeg"))}catch{}e.push((0,m.join)(process.cwd(),"node_modules","ffmpeg-static","ffmpeg"),(0,m.join)(process.cwd(),"node_modules",".pnpm","ffmpeg-static@5.3.0","node_modules","ffmpeg-static","ffmpeg"));for(const t of e)if(t&&!t.startsWith("/ROOT/"))try{return await(0,d.access)(t,Be.constants.X_OK),t}catch{}return null}var j;async function x(){return j!==void 0||(j=await je(),j||console.warn("[ffmpeg-runner] ffmpeg-static \u4E8C\u8FDB\u5236\u672A\u627E\u5230 (\u5C1D\u8BD5\u4E86\u591A\u4E2A fallback \u8DEF\u5F84)")),j}async function B({args:e,timeoutMs:t=18e4}){const u=await x();if(!u)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931 \u2014 \u8BF7\u68C0\u67E5 node_modules/ffmpeg-static/ffmpeg \u662F\u5426\u5B58\u5728");return console.log("[ffmpeg-runner] args:",JSON.stringify(e)),new Promise((n,r)=>{const i=(0,_.spawn)(u,e,{stdio:["ignore","pipe","pipe"]});let a="",p=!1;const s=setTimeout(()=>{p=!0,i.kill("SIGKILL"),r(new Error(`ffmpeg \u8D85\u65F6 (${t}ms)`))},t);i.stderr.on("data",o=>{a+=o.toString(),a.length>8192&&(a=a.slice(-8192))}),i.on("close",o=>{if(clearTimeout(s),p)return;const f=a.slice(-2500);console.log(`[ffmpeg-runner] exit=${o}, stderr tail:
2
- ${f}
3
- ---end---`),o===0?n():r(new Error(`ffmpeg \u9000\u51FA\u7801 ${o}: ${f.slice(-800)}`))}),i.on("error",o=>{clearTimeout(s),r(o)})})}async function O(e){const t=await(0,d.mkdtemp)((0,m.join)((0,De.tmpdir)(),"vtrans-"));try{return await e(t)}finally{(0,d.rm)(t,{recursive:!0,force:!0}).catch(()=>{})}}async function P(e){const t=await x();return t?O(async u=>{const n=(0,m.join)(u,"probe.mp4");return await(0,d.writeFile)(n,e),new Promise(r=>{const i=(0,_.spawn)(t,["-hide_banner","-i",n],{stdio:["ignore","ignore","pipe"]});let a="";const p=setTimeout(()=>{i.kill("SIGKILL"),r(!1)},15e3);i.stderr.on("data",s=>{a+=s.toString(),a.length>16384&&(a=a.slice(-16384))}),i.on("close",()=>{clearTimeout(p),r(/Stream #[^\n]*Audio:/.test(a))}),i.on("error",()=>{clearTimeout(p),r(!1)})})}):!1}async function xe(e){return O(async t=>{const u=(0,m.join)(t,"in.mp4"),n=(0,m.join)(t,"audio.mp3");return await(0,d.writeFile)(u,e),await B({args:["-y","-i",u,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",n],timeoutMs:6e4}),(0,d.readFile)(n)})}var Te=["Fontsize=14","PrimaryColour=&H00FFFFFF","OutlineColour=&H00000000","BackColour=&H80000000","BorderStyle=1","Outline=2","Shadow=0","Alignment=2","MarginV=80","Bold=1"].join(",");async function Pe(e){const t=(await q(e.videoBytes)).durationSeconds;return O(async u=>{const n=(0,m.join)(u,"in.mp4"),r=(0,m.join)(u,"out.mp4");await(0,d.writeFile)(n,e.videoBytes);const i=["-i",n];let a=-1,p=-1;if(e.newAudioBytes){const g=(0,m.join)(u,"new.mp3");await(0,d.writeFile)(g,e.newAudioBytes),a=(i.length-0)/2,i.push("-i",g)}if(e.bgmAudioBytes){const g=(0,m.join)(u,"bgm.mp3");await(0,d.writeFile)(g,e.bgmAudioBytes),p=i.length/2,i.push("-i",g)}const s=e.srtContent&&e.srtContent.trim().length>0;let o=null;s&&(o=(0,m.join)(u,"subs.srt"),await(0,d.writeFile)(o,e.srtContent));const f=e.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${e.videoBytes.length}B (${t.toFixed(2)}s), newAudio=${e.newAudioBytes?.length??0}B, bgm=${e.bgmAudioBytes?.length??0}B@${f}, srt=${e.srtContent?.length??0}chars`);const F=Te.replace(/,/g,"\\,"),w=[];let v,h=!1;s&&o?(w.push(`[0:v]subtitles=${o}:force_style=${F}[v]`),v="[v]",h=!0):v="0:v:0";const A=[];a>=0&&A.push({idx:a,isBgm:!1}),p>=0&&A.push({idx:p,isBgm:!0});let c=null;if(A.length===1)c=`${A[0].idx}:a:0`;else if(A.length>=2){const g=[];for(const E of A)E.isBgm?(w.push(`[${E.idx}:a]volume=${f}[bgm]`),g.push("[bgm]")):g.push(`[${E.idx}:a]`);w.push(`${g.join("")}amix=inputs=${g.length}:duration=first:dropout_transition=0[a]`),c="[a]"}const y=["-y",...i];w.length>0&&y.push("-filter_complex",w.join(";")),y.push("-map",v),c&&y.push("-map",c),h?y.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):y.push("-c:v","copy"),y.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",t.toFixed(3)),y.push(r),await B({args:y,timeoutMs:18e4});const C=c?await x():null;if(C)try{const g=await new Promise(E=>{const b=(0,_.spawn)(C,["-i",r],{stdio:["ignore","pipe","pipe"]});let S="";b.stderr.on("data",H=>S+=H.toString()),b.on("close",()=>E(S))});if(!/Audio:/.test(g))throw console.error(`[ffmpeg-runner] \u4EA7\u7269\u7F3A\u5C11\u97F3\u8F68,ffmpeg \u6D41\u6982\u89C8:
4
- `,g.slice(-2e3)),new Error("\u5408\u6210\u5931\u8D25: \u8F93\u51FA mp4 \u7F3A\u5C11\u97F3\u8F68 (\u68C0\u67E5 filter_complex \u8BED\u6CD5)");console.log("[ffmpeg-runner] composeVideo \u5B8C\u6210,\u5DF2\u542B\u97F3\u89C6\u9891\u53CC\u6D41")}catch(g){if(g instanceof Error&&g.message.includes("\u5408\u6210\u5931\u8D25"))throw g}return(0,d.readFile)(r)})}async function q(e){return O(async t=>{const u=(0,m.join)(t,"in.mp4");await(0,d.writeFile)(u,e);const n=await x();if(!n)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931");return new Promise((r,i)=>{const a=(0,_.spawn)(n,["-i",u],{stdio:["ignore","pipe","pipe"]});let p="";a.stderr.on("data",s=>p+=s.toString()),a.on("close",()=>{const s=p.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!s)return i(new Error("\u65E0\u6CD5\u89E3\u6790\u89C6\u9891\u65F6\u957F"));const o=parseInt(s[1]),f=parseInt(s[2]),F=parseFloat(s[3]);r({durationSeconds:o*3600+f*60+F})}),a.on("error",i)})})}async function $(e,t,u="mp4",n=[],r=24e4){return O(async i=>{const a=(0,m.join)(i,"input.mp4"),p=(0,m.join)(i,`output.${u}`);await(0,d.writeFile)(a,e);const s={};for(const o of n){const f=o.name.replace(/[^a-zA-Z0-9._-]/g,"_"),F=(0,m.join)(i,f);await(0,d.writeFile)(F,o.bytes),s[o.name]=F}return await B({args:t(a,p,s),timeoutMs:r}),(0,d.readFile)(p)})}function $e(e){const t=String(e??"").toLowerCase();return t==="mp4"||t==="mov"}function Se(e,t,u){return["-y","-loop","1","-t","0.04","-i",t,"-i",e,"-filter_complex","[0:v][1:v]scale2ref=w=main_w:h=main_h[vcover][vmainref];[vcover]setsar=1,fps=30,format=yuv420p[vcoverf];[vmainref]setpts=PTS-STARTPTS,fps=30,format=yuv420p[vmain];[vcoverf][vmain]concat=n=2:v=1:a=0[v]","-map","[v]","-map","1:a?","-c:v","libx264","-preset","fast","-crf","18","-pix_fmt","yuv420p","-c:a","copy","-movflags","+faststart",u]}async function Ve(e,t,u="mp4",n=[],r,i=24e4){return O(async a=>{const p=(0,m.join)(a,"input.mp4"),s=(0,m.join)(a,`output.${u}`),o=(0,m.join)(a,"video-cover.png"),f=(0,m.join)(a,`output-with-cover.${u}`);await(0,d.writeFile)(p,e);const F={};for(const w of n){const v=w.name.replace(/[^a-zA-Z0-9._-]/g,"_"),h=(0,m.join)(a,v);await(0,d.writeFile)(h,w.bytes),F[w.name]=h}return await B({args:t(p,s,F),timeoutMs:i}),!$e(u)||!r?.length?(0,d.readFile)(s):(await(0,d.writeFile)(o,r),await B({args:Se(s,o,f),timeoutMs:i}),(0,d.readFile)(f))})}var Y={maxVideos:6,maxAudios:3,maxVideoBytes:100*1024*1024,maxTotalVideoBytes:300*1024*1024,maxAudioBytes:30*1024*1024,maxOverlayBytes:20*1024*1024},l=(e,t,u)=>({ok:!1,status:e,error:t,message:u});function G(e){return e.startsWith("video/")?"mp4":e.includes("mpeg")||e.includes("mp3")?"mp3":e.includes("wav")?"wav":e.includes("aac")?"aac":e.includes("ogg")?"ogg":e.includes("mp4")||e.includes("m4a")?"m4a":e.includes("flac")?"flac":"bin"}function Me(e){if(!e?.poster?.useAsVideoCover)return;const t=(typeof e.poster.preview=="string"?e.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);if(t)return Buffer.from(t[1],"base64")}function Re(e){const t={...Y,...e?.limits};return{async handle(u){const{videos:n,audios:r,overlay:i,videoCover:a,editStateRaw:p}=u;if(n.length>t.maxVideos)return l(413,"TOO_MANY",`\u89C6\u9891\u6570\u8D85\u8FC7 ${t.maxVideos}`);for(let o=0;o<n.length;o++){if(!/^video\//.test(n[o].type))return l(415,"BAD_TYPE",`video_${o} \u4E0D\u662F\u89C6\u9891\u6587\u4EF6`);if(n[o].bytes.length>t.maxVideoBytes)return l(413,"TOO_LARGE",`\u89C6\u9891 ${o+1} \u8D85\u8FC7 100MB`)}if(!n.length)return l(400,"BAD_REQUEST","\u7F3A\u5C11\u89C6\u9891\u6587\u4EF6(video_0)");if(n.reduce((o,f)=>o+f.bytes.length,0)>t.maxTotalVideoBytes)return l(413,"TOO_LARGE","\u89C6\u9891\u603B\u5927\u5C0F\u8D85\u8FC7 300MB,\u8BF7\u51CF\u5C11\u7D20\u6750\u6216\u538B\u7F29");if(r.length>t.maxAudios)return l(413,"TOO_MANY",`\u97F3\u9891\u6570\u8D85\u8FC7 ${t.maxAudios}`);for(let o=0;o<r.length;o++){const f=/^audio\//.test(r[o].type),F=/^video\//.test(r[o].type);if(!f&&!F)return l(415,"BAD_TYPE",`audio_${o} \u4E0D\u662F\u97F3\u9891\u6216\u89C6\u9891\u6587\u4EF6`);if(r[o].bytes.length>(F?t.maxVideoBytes:t.maxAudioBytes))return l(413,"TOO_LARGE",`\u97F3\u9891 ${o+1} \u8D85\u8FC7 ${F?"100MB":"30MB"}`)}if(typeof p!="string")return l(400,"BAD_REQUEST","\u7F3A\u5C11 editState");if(i&&i.length>t.maxOverlayBytes)return l(413,"OVERLAY_TOO_LARGE","overlay \u8FC7\u5927");if(a&&a.length>t.maxOverlayBytes)return l(413,"COVER_TOO_LARGE","videoCover \u8FC7\u5927");let s;try{s=Oe.VideoEditState.parse(JSON.parse(p))}catch{return l(400,"BAD_STATE","\u7F16\u8F91\u53C2\u6570\u4E0D\u5408\u6CD5")}if(s.clips.some(o=>o.srcIdx>=n.length))return l(400,"BAD_STATE","clips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u89C6\u9891\u6570");if((s.audioClips??[]).some(o=>o.srcIdx>=r.length))return l(400,"BAD_STATE","audioClips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u97F3\u9891\u6570");try{const o=n.map(c=>c.bytes),f=r.map(c=>c.bytes),F=[...new Set((s.audioClips??[]).map(c=>c.srcIdx))];for(const c of F)if(/^video\//.test(r[c].type)&&!await P(f[c]))return l(400,"BAD_TYPE",`\u97F3\u9891 ${c+1} \u662F\u89C6\u9891\u6587\u4EF6\u4F46\u6CA1\u6709\u97F3\u8F68,\u65E0\u6CD5\u63D0\u53D6\u58F0\u97F3`);const w=n.map(()=>!1);if(s.keepAudio){const c=[...new Set(s.clips.map(y=>y.srcIdx))];await Promise.all(c.map(async y=>{w[y]=await P(o[y])})),!w.some(Boolean)&&!(s.audioClips??[]).length&&(s={...s,keepAudio:!1})}const v=[];for(let c=1;c<o.length;c++)v.push({name:`video_${c}.mp4`,bytes:o[c]});f.forEach((c,y)=>v.push({name:`audio_${y}.${G(r[y].type)}`,bytes:c})),i&&v.push({name:"overlay.png",bytes:i});const h=a?.length?a:Me(s),A=(c,y,C)=>{const g={videoPaths:[c,...o.slice(1).map((E,b)=>C[`video_${b+1}.mp4`])],videoHasAudio:w,audioPaths:f.map((E,b)=>C[`audio_${b}.${G(r[b].type)}`]),overlayPath:i?C["overlay.png"]:void 0};return(0,N.buildFfmpegArgs)(s,g,y)};return{ok:!0,bytes:h==null?await $(o[0],A,"mp4",v,28e4):await Ve(o[0],A,"mp4",v,h,28e4),contentType:"video/mp4",filename:"edited.mp4"}}catch(o){return(o.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?l(503,"SERVER_NOT_READY","\u670D\u52A1\u7AEF\u7F16\u7801\u7EC4\u4EF6\u672A\u5C31\u7EEA\uFF08ffmpeg \u7F3A\u5931\uFF09\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458"):l(502,"ENCODE_FAILED","\u89C6\u9891\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u6216\u6362\u66F4\u77ED\u7684\u89C6\u9891")}}}}function Ie(e){const t=e?.maxBytes??104857600;return{async handle(u,n){if(!/^video\//.test(u.type))return l(415,"BAD_TYPE","\u53EA\u652F\u6301\u89C6\u9891\u6587\u4EF6");if(u.bytes.length>t)return l(413,"TOO_LARGE","\u6587\u4EF6\u8D85\u8FC7 100MB");if(!isFinite(n)||n<0)return l(400,"BAD_TIME","time \u53C2\u6570\u4E0D\u5408\u6CD5");try{return{ok:!0,bytes:await $(u.bytes,(r,i)=>(0,N.buildPosterArgs)(r,n,i),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}catch(r){return(r.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?l(503,"SERVER_NOT_READY","\u670D\u52A1\u7AEF\u7F16\u7801\u7EC4\u4EF6\u672A\u5C31\u7EEA\uFF08ffmpeg \u7F3A\u5931\uFF09\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458"):l(502,"EXTRACT_FAILED","\u5C01\u9762\u62BD\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5")}}}}
1
+ "use strict";var z=Object.create,V=Object.defineProperty,K=Object.getOwnPropertyDescriptor,U=Object.getOwnPropertyNames,J=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty,W=(e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of U(t))!Q.call(e,n)&&n!==r&&V(e,n,{get:()=>t[n],enumerable:!(o=K(t,n))||o.enumerable});return e},X=(e,t,r)=>(r=null!=e?z(J(e)):{},W(!t&&e&&e.__esModule?r:V(r,"default",{value:e,enumerable:!0}),e)),Z=Object.create,M=Object.defineProperty,ee=Object.getOwnPropertyDescriptor,te=Object.getOwnPropertyNames,ue=Object.getPrototypeOf,re=Object.prototype.hasOwnProperty,oe=(e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of te(t))!re.call(e,n)&&n!==r&&M(e,n,{get:()=>t[n],enumerable:!(o=ee(t,n))||o.enumerable});return e},ke=(e,t,r)=>(r=null!=e?Z(ue(e)):{},oe(!t&&e&&e.__esModule?r:M(r,"default",{value:e,enumerable:!0}),e)),ne=Object.create,R=Object.defineProperty,ie=Object.getOwnPropertyDescriptor,ae=Object.getOwnPropertyNames,se=Object.getPrototypeOf,ce=Object.prototype.hasOwnProperty,le=(e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of ae(t))!ce.call(e,n)&&n!==r&&R(e,n,{get:()=>t[n],enumerable:!(o=ie(t,n))||o.enumerable});return e},Ne=(e,t,r)=>(r=null!=e?ne(se(e)):{},le(!t&&e&&e.__esModule?r:R(r,"default",{value:e,enumerable:!0}),e)),pe=Object.create,I=Object.defineProperty,me=Object.getOwnPropertyDescriptor,fe=Object.getOwnPropertyNames,de=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty,ye=(e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of fe(t))!ge.call(e,n)&&n!==r&&I(e,n,{get:()=>t[n],enumerable:!(o=me(t,n))||o.enumerable});return e},qe=(e,t,r)=>(r=null!=e?pe(de(e)):{},ye(!t&&e&&e.__esModule?r:I(r,"default",{value:e,enumerable:!0}),e)),Fe=Object.create,D=Object.defineProperty,we=Object.getOwnPropertyDescriptor,ve=Object.getOwnPropertyNames,Ae=Object.getPrototypeOf,he=Object.prototype.hasOwnProperty,Ee=(e,t)=>{for(var r in t)D(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,o)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let n of ve(t))!he.call(e,n)&&n!==r&&D(e,n,{get:()=>t[n],enumerable:!(o=we(t,n))||o.enumerable});return e},be=(e,t,r)=>(r=null!=e?Fe(Ae(e)):{},L(!t&&e&&e.__esModule?r:D(r,"default",{value:e,enumerable:!0}),e)),Ce=e=>L(D({},"__esModule",{value:!0}),e),k={};Ee(k,{DEFAULT_LIMITS:()=>Y,composeVideo:()=>Pe,createPosterHandler:()=>Ie,createVideoExportHandler:()=>Re,extractAudio:()=>xe,probeHasAudio:()=>P,probeVideoDuration:()=>q,runVideoEdit:()=>$}),module.exports=Ce(k);var j,Oe=require("../core/dist/index.cjs"),N=require("../core/dist/index.cjs"),T=be(require("ffmpeg-static"),1),_=require("child_process"),d=require("fs/promises"),Be=require("fs"),De=require("os"),m=require("path"),_e={};async function je(){const e=[];T.default&&"string"==typeof T.default&&e.push(T.default);try{const{createRequire:t}=await import("module"),r=t(_e.url).resolve("ffmpeg-static/package.json"),o=r.substring(0,r.lastIndexOf("/"));e.push((0,m.join)(o,"ffmpeg"))}catch{}e.push((0,m.join)(process.cwd(),"node_modules","ffmpeg-static","ffmpeg"),(0,m.join)(process.cwd(),"node_modules",".pnpm","ffmpeg-static@5.3.0","node_modules","ffmpeg-static","ffmpeg"));for(const t of e)if(t&&!t.startsWith("/ROOT/"))try{return await(0,d.access)(t,Be.constants.X_OK),t}catch{}return null}async function x(){return void 0!==j||(j=await je())||console.warn("[ffmpeg-runner] ffmpeg-static 二进制未找到 (尝试了多个 fallback 路径)"),j}async function B({args:e,timeoutMs:t=18e4}){const r=await x();if(!r)throw new Error("ffmpeg-static 二进制缺失 — 请检查 node_modules/ffmpeg-static/ffmpeg 是否存在");return console.log("[ffmpeg-runner] args:",JSON.stringify(e)),new Promise((o,n)=>{const i=(0,_.spawn)(r,e,{stdio:["ignore","pipe","pipe"]});let s="",a=!1;const c=setTimeout(()=>{a=!0,i.kill("SIGKILL"),n(new Error(`ffmpeg 超时 (${t}ms)`))},t);i.stderr.on("data",e=>{s+=e.toString(),s.length>8192&&(s=s.slice(-8192))}),i.on("close",e=>{if(clearTimeout(c),a)return;const t=s.slice(-2500);console.log(`[ffmpeg-runner] exit=${e}, stderr tail:\n${t}\n---end---`),0===e?o():n(new Error(`ffmpeg 退出码 ${e}: ${t.slice(-800)}`))}),i.on("error",e=>{clearTimeout(c),n(e)})})}async function O(e){const t=await(0,d.mkdtemp)((0,m.join)((0,De.tmpdir)(),"vtrans-"));try{return await e(t)}finally{(0,d.rm)(t,{recursive:!0,force:!0}).catch(()=>{})}}async function P(e){const t=await x();return!!t&&O(async r=>{const o=(0,m.join)(r,"probe.mp4");return await(0,d.writeFile)(o,e),new Promise(e=>{const r=(0,_.spawn)(t,["-hide_banner","-i",o],{stdio:["ignore","ignore","pipe"]});let n="";const i=setTimeout(()=>{r.kill("SIGKILL"),e(!1)},15e3);r.stderr.on("data",e=>{n+=e.toString(),n.length>16384&&(n=n.slice(-16384))}),r.on("close",()=>{clearTimeout(i),e(/Stream #[^\n]*Audio:/.test(n))}),r.on("error",()=>{clearTimeout(i),e(!1)})})})}async function xe(e){return O(async t=>{const r=(0,m.join)(t,"in.mp4"),o=(0,m.join)(t,"audio.mp3");return await(0,d.writeFile)(r,e),await B({args:["-y","-i",r,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",o],timeoutMs:6e4}),(0,d.readFile)(o)})}var Te=["Fontsize=14","PrimaryColour=&H00FFFFFF","OutlineColour=&H00000000","BackColour=&H80000000","BorderStyle=1","Outline=2","Shadow=0","Alignment=2","MarginV=80","Bold=1"].join(",");async function Pe(e){const t=(await q(e.videoBytes)).durationSeconds;return O(async r=>{const o=(0,m.join)(r,"in.mp4"),n=(0,m.join)(r,"out.mp4");await(0,d.writeFile)(o,e.videoBytes);const i=["-i",o];let s=-1,a=-1;if(e.newAudioBytes){const t=(0,m.join)(r,"new.mp3");await(0,d.writeFile)(t,e.newAudioBytes),s=(i.length-0)/2,i.push("-i",t)}if(e.bgmAudioBytes){const t=(0,m.join)(r,"bgm.mp3");await(0,d.writeFile)(t,e.bgmAudioBytes),a=i.length/2,i.push("-i",t)}const c=e.srtContent&&e.srtContent.trim().length>0;let l=null;c&&(l=(0,m.join)(r,"subs.srt"),await(0,d.writeFile)(l,e.srtContent));const u=e.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${e.videoBytes.length}B (${t.toFixed(2)}s), newAudio=${e.newAudioBytes?.length??0}B, bgm=${e.bgmAudioBytes?.length??0}B@${u}, srt=${e.srtContent?.length??0}chars`);const p=Te.replace(/,/g,"\\,"),f=[];let g,y=!1;c&&l?(f.push(`[0:v]subtitles=${l}:force_style=${p}[v]`),g="[v]",y=!0):g="0:v:0";const w=[];s>=0&&w.push({idx:s,isBgm:!1}),a>=0&&w.push({idx:a,isBgm:!0});let b=null;if(1===w.length)b=`${w[0].idx}:a:0`;else if(w.length>=2){const e=[];for(const t of w)t.isBgm?(f.push(`[${t.idx}:a]volume=${u}[bgm]`),e.push("[bgm]")):e.push(`[${t.idx}:a]`);f.push(`${e.join("")}amix=inputs=${e.length}:duration=first:dropout_transition=0[a]`),b="[a]"}const O=["-y",...i];f.length>0&&O.push("-filter_complex",f.join(";")),O.push("-map",g),b&&O.push("-map",b),y?O.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):O.push("-c:v","copy"),O.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",t.toFixed(3)),O.push(n),await B({args:O,timeoutMs:18e4});const v=b?await x():null;if(v)try{const e=await new Promise(e=>{const t=(0,_.spawn)(v,["-i",n],{stdio:["ignore","pipe","pipe"]});let r="";t.stderr.on("data",e=>r+=e.toString()),t.on("close",()=>e(r))});if(!/Audio:/.test(e))throw console.error("[ffmpeg-runner] 产物缺少音轨,ffmpeg 流概览:\n",e.slice(-2e3)),new Error("合成失败: 输出 mp4 缺少音轨 (检查 filter_complex 语法)");console.log("[ffmpeg-runner] composeVideo 完成,已含音视频双流")}catch(e){if(e instanceof Error&&e.message.includes("合成失败"))throw e}return(0,d.readFile)(n)})}async function q(e){return O(async t=>{const r=(0,m.join)(t,"in.mp4");await(0,d.writeFile)(r,e);const o=await x();if(!o)throw new Error("ffmpeg-static 二进制缺失");return new Promise((e,t)=>{const n=(0,_.spawn)(o,["-i",r],{stdio:["ignore","pipe","pipe"]});let i="";n.stderr.on("data",e=>i+=e.toString()),n.on("close",()=>{const r=i.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!r)return t(new Error("无法解析视频时长"));const o=parseInt(r[1]),n=parseInt(r[2]),s=parseFloat(r[3]);e({durationSeconds:3600*o+60*n+s})}),n.on("error",t)})})}async function $(e,t,r="mp4",o=[],n=24e4){return O(async i=>{const s=(0,m.join)(i,"input.mp4"),a=(0,m.join)(i,`output.${r}`);await(0,d.writeFile)(s,e);const c={};for(const e of o){const t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),r=(0,m.join)(i,t);await(0,d.writeFile)(r,e.bytes),c[e.name]=r}return await B({args:t(s,a,c),timeoutMs:n}),(0,d.readFile)(a)})}function $e(e){const t=String(e??"").toLowerCase();return"mp4"===t||"mov"===t}function Se(e,t,r){return["-y","-loop","1","-t","0.04","-i",t,"-i",e,"-filter_complex","[0:v][1:v]scale2ref=w=main_w:h=main_h[vcover][vmainref];[vcover]setsar=1,fps=30,format=yuv420p[vcoverf];[vmainref]setpts=PTS-STARTPTS,fps=30,format=yuv420p[vmain];[vcoverf][vmain]concat=n=2:v=1:a=0[v]","-map","[v]","-map","1:a?","-c:v","libx264","-preset","fast","-crf","18","-pix_fmt","yuv420p","-c:a","copy","-movflags","+faststart",r]}async function Ve(e,t,r="mp4",o=[],n,i=24e4){return O(async s=>{const a=(0,m.join)(s,"input.mp4"),c=(0,m.join)(s,`output.${r}`),l=(0,m.join)(s,"video-cover.png"),u=(0,m.join)(s,`output-with-cover.${r}`);await(0,d.writeFile)(a,e);const p={};for(const e of o){const t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),r=(0,m.join)(s,t);await(0,d.writeFile)(r,e.bytes),p[e.name]=r}return await B({args:t(a,c,p),timeoutMs:i}),$e(r)&&n?.length?(await(0,d.writeFile)(l,n),await B({args:Se(c,l,u),timeoutMs:i}),(0,d.readFile)(u)):(0,d.readFile)(c)})}var Y={maxVideos:6,maxAudios:3,maxVideoBytes:104857600,maxTotalVideoBytes:314572800,maxAudioBytes:31457280,maxOverlayBytes:20971520},l=(e,t,r)=>({ok:!1,status:e,error:t,message:r});function G(e){return e.startsWith("video/")?"mp4":e.includes("mpeg")||e.includes("mp3")?"mp3":e.includes("wav")?"wav":e.includes("aac")?"aac":e.includes("ogg")?"ogg":e.includes("mp4")||e.includes("m4a")?"m4a":e.includes("flac")?"flac":"bin"}function Me(e){if(!e?.poster?.useAsVideoCover)return;const t=("string"==typeof e.poster.preview?e.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);return t?Buffer.from(t[1],"base64"):void 0}function Re(e){const t={...Y,...e?.limits};return{async handle(e){const{videos:r,audios:o,overlay:n,videoCover:i,editStateRaw:s}=e;if(r.length>t.maxVideos)return l(413,"TOO_MANY",`视频数超过 ${t.maxVideos}`);for(let e=0;e<r.length;e++){if(!/^video\//.test(r[e].type))return l(415,"BAD_TYPE",`video_${e} 不是视频文件`);if(r[e].bytes.length>t.maxVideoBytes)return l(413,"TOO_LARGE",`视频 ${e+1} 超过 100MB`)}if(!r.length)return l(400,"BAD_REQUEST","缺少视频文件(video_0)");if(r.reduce((e,t)=>e+t.bytes.length,0)>t.maxTotalVideoBytes)return l(413,"TOO_LARGE","视频总大小超过 300MB,请减少素材或压缩");if(o.length>t.maxAudios)return l(413,"TOO_MANY",`音频数超过 ${t.maxAudios}`);for(let e=0;e<o.length;e++){const r=/^audio\//.test(o[e].type),n=/^video\//.test(o[e].type);if(!r&&!n)return l(415,"BAD_TYPE",`audio_${e} 不是音频或视频文件`);if(o[e].bytes.length>(n?t.maxVideoBytes:t.maxAudioBytes))return l(413,"TOO_LARGE",`音频 ${e+1} 超过 ${n?"100MB":"30MB"}`)}if("string"!=typeof s)return l(400,"BAD_REQUEST","缺少 editState");if(n&&n.length>t.maxOverlayBytes)return l(413,"OVERLAY_TOO_LARGE","overlay 过大");if(i&&i.length>t.maxOverlayBytes)return l(413,"COVER_TOO_LARGE","videoCover 过大");let a;try{a=Oe.VideoEditState.parse(JSON.parse(s))}catch{return l(400,"BAD_STATE","编辑参数不合法")}if(a.clips.some(e=>e.srcIdx>=r.length))return l(400,"BAD_STATE","clips.srcIdx 超出上传视频数");if((a.audioClips??[]).some(e=>e.srcIdx>=o.length))return l(400,"BAD_STATE","audioClips.srcIdx 超出上传音频数");try{const e=r.map(e=>e.bytes),t=o.map(e=>e.bytes),s=[...new Set((a.audioClips??[]).map(e=>e.srcIdx))];for(const e of s)if(/^video\//.test(o[e].type)&&!await P(t[e]))return l(400,"BAD_TYPE",`音频 ${e+1} 是视频文件但没有音轨,无法提取声音`);const c=r.map(()=>!1);if(a.keepAudio){const t=[...new Set(a.clips.map(e=>e.srcIdx))];await Promise.all(t.map(async t=>{c[t]=await P(e[t])})),!c.some(Boolean)&&!(a.audioClips??[]).length&&(a={...a,keepAudio:!1})}const u=[];for(let t=1;t<e.length;t++)u.push({name:`video_${t}.mp4`,bytes:e[t]});t.forEach((e,t)=>u.push({name:`audio_${t}.${G(o[t].type)}`,bytes:e})),n&&u.push({name:"overlay.png",bytes:n});const p=i?.length?i:Me(a),m=(r,i,s)=>{const l={videoPaths:[r,...e.slice(1).map((e,t)=>s[`video_${t+1}.mp4`])],videoHasAudio:c,audioPaths:t.map((e,t)=>s[`audio_${t}.${G(o[t].type)}`]),overlayPath:n?s["overlay.png"]:void 0};return(0,N.buildFfmpegArgs)(a,l,i)};return{ok:!0,bytes:null==p?await $(e[0],m,"mp4",u,28e4):await Ve(e[0],m,"mp4",u,p,28e4),contentType:"video/mp4",filename:"edited.mp4"}}catch(e){return(e.message??"").includes("二进制缺失")?l(503,"SERVER_NOT_READY","服务端编码组件未就绪(ffmpeg 缺失),请联系管理员"):l(502,"ENCODE_FAILED","视频处理失败,请重试或换更短的视频")}}}}function Ie(e){const t=e?.maxBytes??104857600;return{async handle(e,r){if(!/^video\//.test(e.type))return l(415,"BAD_TYPE","只支持视频文件");if(e.bytes.length>t)return l(413,"TOO_LARGE","文件超过 100MB");if(!isFinite(r)||r<0)return l(400,"BAD_TIME","time 参数不合法");try{return{ok:!0,bytes:await $(e.bytes,(e,t)=>(0,N.buildPosterArgs)(e,r,t),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}catch(e){return(e.message??"").includes("二进制缺失")?l(503,"SERVER_NOT_READY","服务端编码组件未就绪(ffmpeg 缺失),请联系管理员"):l(502,"EXTRACT_FAILED","封面抽取失败,请重试")}}}}
package/dist/index.js CHANGED
@@ -1,4 +1 @@
1
- import{VideoEditState as k}from"../core/dist/index.js";import{buildFfmpegArgs as Y,buildPosterArgs as j}from"../core/dist/index.js";import R from"ffmpeg-static";import{spawn as b}from"child_process";import{writeFile as v,readFile as x,mkdtemp as G,rm as H,access as N}from"fs/promises";import{constants as z}from"fs";import{tmpdir as K}from"os";import{join as d}from"path";async function U(){const t=[];R&&typeof R=="string"&&t.push(R);try{const{createRequire:e}=await import("module"),o=e(import.meta.url).resolve("ffmpeg-static/package.json"),r=o.substring(0,o.lastIndexOf("/"));t.push(d(r,"ffmpeg"))}catch{}t.push(d(process.cwd(),"node_modules","ffmpeg-static","ffmpeg"),d(process.cwd(),"node_modules",".pnpm","ffmpeg-static@5.3.0","node_modules","ffmpeg-static","ffmpeg"));for(const e of t)if(e&&!e.startsWith("/ROOT/"))try{return await N(e,z.X_OK),e}catch{}return null}var $;async function S(){return $!==void 0||($=await U(),$||console.warn("[ffmpeg-runner] ffmpeg-static \u4E8C\u8FDB\u5236\u672A\u627E\u5230 (\u5C1D\u8BD5\u4E86\u591A\u4E2A fallback \u8DEF\u5F84)")),$}async function T({args:t,timeoutMs:e=18e4}){const o=await S();if(!o)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931 \u2014 \u8BF7\u68C0\u67E5 node_modules/ffmpeg-static/ffmpeg \u662F\u5426\u5B58\u5728");return console.log("[ffmpeg-runner] args:",JSON.stringify(t)),new Promise((r,s)=>{const a=b(o,t,{stdio:["ignore","pipe","pipe"]});let i="",f=!1;const m=setTimeout(()=>{f=!0,a.kill("SIGKILL"),s(new Error(`ffmpeg \u8D85\u65F6 (${e}ms)`))},e);a.stderr.on("data",n=>{i+=n.toString(),i.length>8192&&(i=i.slice(-8192))}),a.on("close",n=>{if(clearTimeout(m),f)return;const u=i.slice(-2500);console.log(`[ffmpeg-runner] exit=${n}, stderr tail:
2
- ${u}
3
- ---end---`),n===0?r():s(new Error(`ffmpeg \u9000\u51FA\u7801 ${n}: ${u.slice(-800)}`))}),a.on("error",n=>{clearTimeout(m),s(n)})})}async function D(t){const e=await G(d(K(),"vtrans-"));try{return await t(e)}finally{H(e,{recursive:!0,force:!0}).catch(()=>{})}}async function V(t){const e=await S();return e?D(async o=>{const r=d(o,"probe.mp4");return await v(r,t),new Promise(s=>{const a=b(e,["-hide_banner","-i",r],{stdio:["ignore","ignore","pipe"]});let i="";const f=setTimeout(()=>{a.kill("SIGKILL"),s(!1)},15e3);a.stderr.on("data",m=>{i+=m.toString(),i.length>16384&&(i=i.slice(-16384))}),a.on("close",()=>{clearTimeout(f),s(/Stream #[^\n]*Audio:/.test(i))}),a.on("error",()=>{clearTimeout(f),s(!1)})})}):!1}async function q(t){return D(async e=>{const o=d(e,"in.mp4"),r=d(e,"audio.mp3");return await v(o,t),await T({args:["-y","-i",o,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",r],timeoutMs:6e4}),x(r)})}var J=["Fontsize=14","PrimaryColour=&H00FFFFFF","OutlineColour=&H00000000","BackColour=&H80000000","BorderStyle=1","Outline=2","Shadow=0","Alignment=2","MarginV=80","Bold=1"].join(",");async function Q(t){const e=(await I(t.videoBytes)).durationSeconds;return D(async o=>{const r=d(o,"in.mp4"),s=d(o,"out.mp4");await v(r,t.videoBytes);const a=["-i",r];let i=-1,f=-1;if(t.newAudioBytes){const c=d(o,"new.mp3");await v(c,t.newAudioBytes),i=(a.length-0)/2,a.push("-i",c)}if(t.bgmAudioBytes){const c=d(o,"bgm.mp3");await v(c,t.bgmAudioBytes),f=a.length/2,a.push("-i",c)}const m=t.srtContent&&t.srtContent.trim().length>0;let n=null;m&&(n=d(o,"subs.srt"),await v(n,t.srtContent));const u=t.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${t.videoBytes.length}B (${e.toFixed(2)}s), newAudio=${t.newAudioBytes?.length??0}B, bgm=${t.bgmAudioBytes?.length??0}B@${u}, srt=${t.srtContent?.length??0}chars`);const g=J.replace(/,/g,"\\,"),F=[];let C,y=!1;m&&n?(F.push(`[0:v]subtitles=${n}:force_style=${g}[v]`),C="[v]",y=!0):C="0:v:0";const A=[];i>=0&&A.push({idx:i,isBgm:!1}),f>=0&&A.push({idx:f,isBgm:!0});let w=null;if(A.length===1)w=`${A[0].idx}:a:0`;else if(A.length>=2){const c=[];for(const h of A)h.isBgm?(F.push(`[${h.idx}:a]volume=${u}[bgm]`),c.push("[bgm]")):c.push(`[${h.idx}:a]`);F.push(`${c.join("")}amix=inputs=${c.length}:duration=first:dropout_transition=0[a]`),w="[a]"}const E=["-y",...a];F.length>0&&E.push("-filter_complex",F.join(";")),E.push("-map",C),w&&E.push("-map",w),y?E.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):E.push("-c:v","copy"),E.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",e.toFixed(3)),E.push(s),await T({args:E,timeoutMs:18e4});const p=w?await S():null;if(p)try{const c=await new Promise(h=>{const O=b(p,["-i",s],{stdio:["ignore","pipe","pipe"]});let _="";O.stderr.on("data",B=>_+=B.toString()),O.on("close",()=>h(_))});if(!/Audio:/.test(c))throw console.error(`[ffmpeg-runner] \u4EA7\u7269\u7F3A\u5C11\u97F3\u8F68,ffmpeg \u6D41\u6982\u89C8:
4
- `,c.slice(-2e3)),new Error("\u5408\u6210\u5931\u8D25: \u8F93\u51FA mp4 \u7F3A\u5C11\u97F3\u8F68 (\u68C0\u67E5 filter_complex \u8BED\u6CD5)");console.log("[ffmpeg-runner] composeVideo \u5B8C\u6210,\u5DF2\u542B\u97F3\u89C6\u9891\u53CC\u6D41")}catch(c){if(c instanceof Error&&c.message.includes("\u5408\u6210\u5931\u8D25"))throw c}return x(s)})}async function I(t){return D(async e=>{const o=d(e,"in.mp4");await v(o,t);const r=await S();if(!r)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931");return new Promise((s,a)=>{const i=b(r,["-i",o],{stdio:["ignore","pipe","pipe"]});let f="";i.stderr.on("data",m=>f+=m.toString()),i.on("close",()=>{const m=f.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!m)return a(new Error("\u65E0\u6CD5\u89E3\u6790\u89C6\u9891\u65F6\u957F"));const n=parseInt(m[1]),u=parseInt(m[2]),g=parseFloat(m[3]);s({durationSeconds:n*3600+u*60+g})}),i.on("error",a)})})}async function L(t,e,o="mp4",r=[],s=24e4){return D(async a=>{const i=d(a,"input.mp4"),f=d(a,`output.${o}`);await v(i,t);const m={};for(const n of r){const u=n.name.replace(/[^a-zA-Z0-9._-]/g,"_"),g=d(a,u);await v(g,n.bytes),m[n.name]=g}return await T({args:e(i,f,m),timeoutMs:s}),x(f)})}function W(t){const e=String(t??"").toLowerCase();return e==="mp4"||e==="mov"}function X(t,e,o){return["-y","-loop","1","-t","0.04","-i",e,"-i",t,"-filter_complex","[0:v][1:v]scale2ref=w=main_w:h=main_h[vcover][vmainref];[vcover]setsar=1,fps=30,format=yuv420p[vcoverf];[vmainref]setpts=PTS-STARTPTS,fps=30,format=yuv420p[vmain];[vcoverf][vmain]concat=n=2:v=1:a=0[v]","-map","[v]","-map","1:a?","-c:v","libx264","-preset","fast","-crf","18","-pix_fmt","yuv420p","-c:a","copy","-movflags","+faststart",o]}async function Z(t,e,o="mp4",r=[],s,a=24e4){return D(async i=>{const f=d(i,"input.mp4"),m=d(i,`output.${o}`),n=d(i,"video-cover.png"),u=d(i,`output-with-cover.${o}`);await v(f,t);const g={};for(const F of r){const C=F.name.replace(/[^a-zA-Z0-9._-]/g,"_"),y=d(i,C);await v(y,F.bytes),g[F.name]=y}return await T({args:e(f,m,g),timeoutMs:a}),!W(o)||!s?.length?x(m):(await v(n,s),await T({args:X(m,n,u),timeoutMs:a}),x(u))})}var P={maxVideos:6,maxAudios:3,maxVideoBytes:100*1024*1024,maxTotalVideoBytes:300*1024*1024,maxAudioBytes:30*1024*1024,maxOverlayBytes:20*1024*1024},l=(t,e,o)=>({ok:!1,status:t,error:e,message:o});function M(t){return t.startsWith("video/")?"mp4":t.includes("mpeg")||t.includes("mp3")?"mp3":t.includes("wav")?"wav":t.includes("aac")?"aac":t.includes("ogg")?"ogg":t.includes("mp4")||t.includes("m4a")?"m4a":t.includes("flac")?"flac":"bin"}function tt(t){const e=String(t??"mp4").toLowerCase();return e==="mov"||e==="mxf"?e:"mp4"}function et(t){return t==="mov"?"video/quicktime":t==="mxf"?"application/mxf":"video/mp4"}function ut(t){if(!t?.poster?.useAsVideoCover)return;const e=(typeof t.poster.preview=="string"?t.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);if(e)return Buffer.from(e[1],"base64")}function ot(t){const e={...P,...t?.limits};return{async handle(o){const{videos:r,audios:s,overlay:a,videoCover:i,textOverlays:f=[],editStateRaw:m}=o;if(r.length>e.maxVideos)return l(413,"TOO_MANY",`\u89C6\u9891\u6570\u8D85\u8FC7 ${e.maxVideos}`);for(let u=0;u<r.length;u++){if(!/^video\//.test(r[u].type))return l(415,"BAD_TYPE",`video_${u} \u4E0D\u662F\u89C6\u9891\u6587\u4EF6`);if(r[u].bytes.length>e.maxVideoBytes)return l(413,"TOO_LARGE",`\u89C6\u9891 ${u+1} \u8D85\u8FC7 100MB`)}if(!r.length)return l(400,"BAD_REQUEST","\u7F3A\u5C11\u89C6\u9891\u6587\u4EF6(video_0)");if(r.reduce((u,g)=>u+g.bytes.length,0)>e.maxTotalVideoBytes)return l(413,"TOO_LARGE","\u89C6\u9891\u603B\u5927\u5C0F\u8D85\u8FC7 300MB,\u8BF7\u51CF\u5C11\u7D20\u6750\u6216\u538B\u7F29");if(s.length>e.maxAudios)return l(413,"TOO_MANY",`\u97F3\u9891\u6570\u8D85\u8FC7 ${e.maxAudios}`);for(let u=0;u<s.length;u++){const g=/^audio\//.test(s[u].type),F=/^video\//.test(s[u].type);if(!g&&!F)return l(415,"BAD_TYPE",`audio_${u} \u4E0D\u662F\u97F3\u9891\u6216\u89C6\u9891\u6587\u4EF6`);if(s[u].bytes.length>(F?e.maxVideoBytes:e.maxAudioBytes))return l(413,"TOO_LARGE",`\u97F3\u9891 ${u+1} \u8D85\u8FC7 ${F?"100MB":"30MB"}`)}if(typeof m!="string")return l(400,"BAD_REQUEST","\u7F3A\u5C11 editState");if(a&&a.length>e.maxOverlayBytes)return l(413,"OVERLAY_TOO_LARGE","overlay \u8FC7\u5927");if(i&&i.length>e.maxOverlayBytes)return l(413,"COVER_TOO_LARGE","videoCover \u8FC7\u5927");if(f.some(u=>u.length>e.maxOverlayBytes))return l(413,"OVERLAY_TOO_LARGE","textOverlay \u8FC7\u5927");let n;try{n=k.parse(JSON.parse(m))}catch{return l(400,"BAD_STATE","\u7F16\u8F91\u53C2\u6570\u4E0D\u5408\u6CD5")}if(n.clips.some(u=>u.srcIdx>=r.length))return l(400,"BAD_STATE","clips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u89C6\u9891\u6570");if((n.audioClips??[]).some(u=>u.srcIdx>=s.length))return l(400,"BAD_STATE","audioClips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u97F3\u9891\u6570");try{const u=r.map(p=>p.bytes),g=s.map(p=>p.bytes),F=[...new Set((n.audioClips??[]).map(p=>p.srcIdx))];for(const p of F)if(/^video\//.test(s[p].type)&&!await V(g[p]))return l(400,"BAD_TYPE",`\u97F3\u9891 ${p+1} \u662F\u89C6\u9891\u6587\u4EF6\u4F46\u6CA1\u6709\u97F3\u8F68,\u65E0\u6CD5\u63D0\u53D6\u58F0\u97F3`);const C=r.map(()=>!1);if(n.keepAudio){const p=[...new Set(n.clips.map(c=>c.srcIdx))];await Promise.all(p.map(async c=>{C[c]=await V(u[c])})),!C.some(Boolean)&&!(n.audioClips??[]).length&&(n={...n,keepAudio:!1})}const y=[];for(let p=1;p<u.length;p++)y.push({name:`video_${p}.mp4`,bytes:u[p]});g.forEach((p,c)=>y.push({name:`audio_${c}.${M(s[c].type)}`,bytes:p})),a&&y.push({name:"overlay.png",bytes:a}),f.forEach((p,c)=>y.push({name:`textOverlay_${c}.png`,bytes:p}));const A=tt(n.exportSettings?.format),w=i?.length?i:ut(n),E=(p,c,h)=>{const O={videoPaths:[p,...u.slice(1).map((_,B)=>h[`video_${B+1}.mp4`])],videoHasAudio:C,audioPaths:g.map((_,B)=>h[`audio_${B}.${M(s[B].type)}`]),overlayPath:a?h["overlay.png"]:void 0,textOverlayPaths:f.map((_,B)=>h[`textOverlay_${B}.png`]).filter(Boolean)};return Y(n,O,c)};return{ok:!0,bytes:w==null?await L(u[0],E,A,y,28e4):await Z(u[0],E,A,y,w,28e4),contentType:et(A),filename:`edited.${A}`}}catch(u){return(u.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?l(503,"SERVER_NOT_READY","\u670D\u52A1\u7AEF\u7F16\u7801\u7EC4\u4EF6\u672A\u5C31\u7EEA\uFF08ffmpeg \u7F3A\u5931\uFF09\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458"):l(502,"ENCODE_FAILED","\u89C6\u9891\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u6216\u6362\u66F4\u77ED\u7684\u89C6\u9891")}}}}function nt(t){const e=t?.maxBytes??104857600;return{async handle(o,r){if(!/^video\//.test(o.type))return l(415,"BAD_TYPE","\u53EA\u652F\u6301\u89C6\u9891\u6587\u4EF6");if(o.bytes.length>e)return l(413,"TOO_LARGE","\u6587\u4EF6\u8D85\u8FC7 100MB");if(!isFinite(r)||r<0)return l(400,"BAD_TIME","time \u53C2\u6570\u4E0D\u5408\u6CD5");try{return{ok:!0,bytes:await L(o.bytes,(s,a)=>j(s,r,a),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}catch(s){return(s.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?l(503,"SERVER_NOT_READY","\u670D\u52A1\u7AEF\u7F16\u7801\u7EC4\u4EF6\u672A\u5C31\u7EEA\uFF08ffmpeg \u7F3A\u5931\uFF09\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458"):l(502,"EXTRACT_FAILED","\u5C01\u9762\u62BD\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5")}}}}export{P as DEFAULT_LIMITS,Q as composeVideo,nt as createPosterHandler,ot as createVideoExportHandler,q as extractAudio,V as probeHasAudio,I as probeVideoDuration,L as runVideoEdit};
1
+ import{VideoEditState as e}from"../core/dist/index.js";import{buildFfmpegArgs as t,buildPosterArgs as o}from"../core/dist/index.js";import s from"ffmpeg-static";import{spawn as n}from"child_process";import{writeFile as r,readFile as i,mkdtemp as a,rm as c,access as u}from"fs/promises";import{constants as m}from"fs";import{tmpdir as p}from"os";import{join as l}from"path";var f;async function d(){return void 0!==f||(f=await async function(){const e=[];s&&"string"==typeof s&&e.push(s);try{const{createRequire:t}=await import("module"),o=t(import.meta.url).resolve("ffmpeg-static/package.json"),s=o.substring(0,o.lastIndexOf("/"));e.push(l(s,"ffmpeg"))}catch{}e.push(l(process.cwd(),"node_modules","ffmpeg-static","ffmpeg"),l(process.cwd(),"node_modules",".pnpm","ffmpeg-static@5.3.0","node_modules","ffmpeg-static","ffmpeg"));for(const t of e)if(t&&!t.startsWith("/ROOT/"))try{return await u(t,m.X_OK),t}catch{}return null}())||console.warn("[ffmpeg-runner] ffmpeg-static 二进制未找到 (尝试了多个 fallback 路径)"),f}async function g({args:e,timeoutMs:t=18e4}){const o=await d();if(!o)throw new Error("ffmpeg-static 二进制缺失 — 请检查 node_modules/ffmpeg-static/ffmpeg 是否存在");return console.log("[ffmpeg-runner] args:",JSON.stringify(e)),new Promise((s,r)=>{const i=n(o,e,{stdio:["ignore","pipe","pipe"]});let a="",c=!1;const u=setTimeout(()=>{c=!0,i.kill("SIGKILL"),r(new Error(`ffmpeg 超时 (${t}ms)`))},t);i.stderr.on("data",e=>{a+=e.toString(),a.length>8192&&(a=a.slice(-8192))}),i.on("close",e=>{if(clearTimeout(u),c)return;const t=a.slice(-2500);console.log(`[ffmpeg-runner] exit=${e}, stderr tail:\n${t}\n---end---`),0===e?s():r(new Error(`ffmpeg 退出码 ${e}: ${t.slice(-800)}`))}),i.on("error",e=>{clearTimeout(u),r(e)})})}async function y(e){const t=await a(l(p(),"vtrans-"));try{return await e(t)}finally{c(t,{recursive:!0,force:!0}).catch(()=>{})}}async function v(e){const t=await d();return!!t&&y(async o=>{const s=l(o,"probe.mp4");return await r(s,e),new Promise(e=>{const o=n(t,["-hide_banner","-i",s],{stdio:["ignore","ignore","pipe"]});let r="";const i=setTimeout(()=>{o.kill("SIGKILL"),e(!1)},15e3);o.stderr.on("data",e=>{r+=e.toString(),r.length>16384&&(r=r.slice(-16384))}),o.on("close",()=>{clearTimeout(i),e(/Stream #[^\n]*Audio:/.test(r))}),o.on("error",()=>{clearTimeout(i),e(!1)})})})}async function h(e){return y(async t=>{const o=l(t,"in.mp4"),s=l(t,"audio.mp3");return await r(o,e),await g({args:["-y","-i",o,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",s],timeoutMs:6e4}),i(s)})}var w=["Fontsize=14","PrimaryColour=&H00FFFFFF","OutlineColour=&H00000000","BackColour=&H80000000","BorderStyle=1","Outline=2","Shadow=0","Alignment=2","MarginV=80","Bold=1"].join(",");async function _(e){const t=(await A(e.videoBytes)).durationSeconds;return y(async o=>{const s=l(o,"in.mp4"),a=l(o,"out.mp4");await r(s,e.videoBytes);const c=["-i",s];let u=-1,m=-1;if(e.newAudioBytes){const t=l(o,"new.mp3");await r(t,e.newAudioBytes),u=(c.length-0)/2,c.push("-i",t)}if(e.bgmAudioBytes){const t=l(o,"bgm.mp3");await r(t,e.bgmAudioBytes),m=c.length/2,c.push("-i",t)}const p=e.srtContent&&e.srtContent.trim().length>0;let f=null;p&&(f=l(o,"subs.srt"),await r(f,e.srtContent));const y=e.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${e.videoBytes.length}B (${t.toFixed(2)}s), newAudio=${e.newAudioBytes?.length??0}B, bgm=${e.bgmAudioBytes?.length??0}B@${y}, srt=${e.srtContent?.length??0}chars`);const v=w.replace(/,/g,"\\,"),h=[];let _,A=!1;p&&f?(h.push(`[0:v]subtitles=${f}:force_style=${v}[v]`),_="[v]",A=!0):_="0:v:0";const x=[];u>=0&&x.push({idx:u,isBgm:!1}),m>=0&&x.push({idx:m,isBgm:!0});let B=null;if(1===x.length)B=`${x[0].idx}:a:0`;else if(x.length>=2){const e=[];for(const t of x)t.isBgm?(h.push(`[${t.idx}:a]volume=${y}[bgm]`),e.push("[bgm]")):e.push(`[${t.idx}:a]`);h.push(`${e.join("")}amix=inputs=${e.length}:duration=first:dropout_transition=0[a]`),B="[a]"}const E=["-y",...c];h.length>0&&E.push("-filter_complex",h.join(";")),E.push("-map",_),B&&E.push("-map",B),A?E.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):E.push("-c:v","copy"),E.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",t.toFixed(3)),E.push(a),await g({args:E,timeoutMs:18e4});const T=B?await d():null;if(T)try{const e=await new Promise(e=>{const t=n(T,["-i",a],{stdio:["ignore","pipe","pipe"]});let o="";t.stderr.on("data",e=>o+=e.toString()),t.on("close",()=>e(o))});if(!/Audio:/.test(e))throw console.error("[ffmpeg-runner] 产物缺少音轨,ffmpeg 流概览:\n",e.slice(-2e3)),new Error("合成失败: 输出 mp4 缺少音轨 (检查 filter_complex 语法)");console.log("[ffmpeg-runner] composeVideo 完成,已含音视频双流")}catch(e){if(e instanceof Error&&e.message.includes("合成失败"))throw e}return i(a)})}async function A(e){return y(async t=>{const o=l(t,"in.mp4");await r(o,e);const s=await d();if(!s)throw new Error("ffmpeg-static 二进制缺失");return new Promise((e,t)=>{const r=n(s,["-i",o],{stdio:["ignore","pipe","pipe"]});let i="";r.stderr.on("data",e=>i+=e.toString()),r.on("close",()=>{const o=i.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!o)return t(new Error("无法解析视频时长"));const s=parseInt(o[1]),n=parseInt(o[2]),r=parseFloat(o[3]);e({durationSeconds:3600*s+60*n+r})}),r.on("error",t)})})}async function x(e,t,o="mp4",s=[],n=24e4){return y(async a=>{const c=l(a,"input.mp4"),u=l(a,`output.${o}`);await r(c,e);const m={};for(const e of s){const t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),o=l(a,t);await r(o,e.bytes),m[e.name]=o}return await g({args:t(c,u,m),timeoutMs:n}),i(u)})}function B(e,t,o){return["-y","-loop","1","-t","0.04","-i",t,"-i",e,"-filter_complex","[0:v][1:v]scale2ref=w=main_w:h=main_h[vcover][vmainref];[vcover]setsar=1,fps=30,format=yuv420p[vcoverf];[vmainref]setpts=PTS-STARTPTS,fps=30,format=yuv420p[vmain];[vcoverf][vmain]concat=n=2:v=1:a=0[v]","-map","[v]","-map","1:a?","-c:v","libx264","-preset","fast","-crf","18","-pix_fmt","yuv420p","-c:a","copy","-movflags","+faststart",o]}async function E(e,t,o="mp4",s=[],n,a=24e4){return y(async c=>{const u=l(c,"input.mp4"),m=l(c,`output.${o}`),p=l(c,"video-cover.png"),f=l(c,`output-with-cover.${o}`);await r(u,e);const d={};for(const e of s){const t=e.name.replace(/[^a-zA-Z0-9._-]/g,"_"),o=l(c,t);await r(o,e.bytes),d[e.name]=o}return await g({args:t(u,m,d),timeoutMs:a}),function(e){const t=String(e??"").toLowerCase();return"mp4"===t||"mov"===t}(o)&&n?.length?(await r(p,n),await g({args:B(m,p,f),timeoutMs:a}),i(f)):i(m)})}var T={maxVideos:6,maxAudios:3,maxVideoBytes:104857600,maxTotalVideoBytes:314572800,maxAudioBytes:31457280,maxOverlayBytes:20971520},b=(e,t,o)=>({ok:!1,status:e,error:t,message:o});function O(e){return e.startsWith("video/")?"mp4":e.includes("mpeg")||e.includes("mp3")?"mp3":e.includes("wav")?"wav":e.includes("aac")?"aac":e.includes("ogg")?"ogg":e.includes("mp4")||e.includes("m4a")?"m4a":e.includes("flac")?"flac":"bin"}function $(e){return"mov"===e?"video/quicktime":"mxf"===e?"application/mxf":"video/mp4"}function S(o){const s={...T,...o?.limits};return{async handle(o){const{videos:n,audios:r,overlay:i,videoCover:a,textOverlays:c=[],editStateRaw:u}=o;if(n.length>s.maxVideos)return b(413,"TOO_MANY",`视频数超过 ${s.maxVideos}`);for(let e=0;e<n.length;e++){if(!/^video\//.test(n[e].type))return b(415,"BAD_TYPE",`video_${e} 不是视频文件`);if(n[e].bytes.length>s.maxVideoBytes)return b(413,"TOO_LARGE",`视频 ${e+1} 超过 100MB`)}if(!n.length)return b(400,"BAD_REQUEST","缺少视频文件(video_0)");if(n.reduce((e,t)=>e+t.bytes.length,0)>s.maxTotalVideoBytes)return b(413,"TOO_LARGE","视频总大小超过 300MB,请减少素材或压缩");if(r.length>s.maxAudios)return b(413,"TOO_MANY",`音频数超过 ${s.maxAudios}`);for(let e=0;e<r.length;e++){const t=/^audio\//.test(r[e].type),o=/^video\//.test(r[e].type);if(!t&&!o)return b(415,"BAD_TYPE",`audio_${e} 不是音频或视频文件`);if(r[e].bytes.length>(o?s.maxVideoBytes:s.maxAudioBytes))return b(413,"TOO_LARGE",`音频 ${e+1} 超过 ${o?"100MB":"30MB"}`)}if("string"!=typeof u)return b(400,"BAD_REQUEST","缺少 editState");if(i&&i.length>s.maxOverlayBytes)return b(413,"OVERLAY_TOO_LARGE","overlay 过大");if(a&&a.length>s.maxOverlayBytes)return b(413,"COVER_TOO_LARGE","videoCover 过大");if(c.some(e=>e.length>s.maxOverlayBytes))return b(413,"OVERLAY_TOO_LARGE","textOverlay 过大");let m;try{m=e.parse(JSON.parse(u))}catch{return b(400,"BAD_STATE","编辑参数不合法")}if(m.clips.some(e=>e.srcIdx>=n.length))return b(400,"BAD_STATE","clips.srcIdx 超出上传视频数");if((m.audioClips??[]).some(e=>e.srcIdx>=r.length))return b(400,"BAD_STATE","audioClips.srcIdx 超出上传音频数");try{const e=n.map(e=>e.bytes),o=r.map(e=>e.bytes),s=[...new Set((m.audioClips??[]).map(e=>e.srcIdx))];for(const e of s)if(/^video\//.test(r[e].type)&&!await v(o[e]))return b(400,"BAD_TYPE",`音频 ${e+1} 是视频文件但没有音轨,无法提取声音`);const u=n.map(()=>!1);if(m.keepAudio){const t=[...new Set(m.clips.map(e=>e.srcIdx))];await Promise.all(t.map(async t=>{u[t]=await v(e[t])})),!u.some(Boolean)&&!(m.audioClips??[]).length&&(m={...m,keepAudio:!1})}const p=[];for(let t=1;t<e.length;t++)p.push({name:`video_${t}.mp4`,bytes:e[t]});o.forEach((e,t)=>p.push({name:`audio_${t}.${O(r[t].type)}`,bytes:e})),i&&p.push({name:"overlay.png",bytes:i}),c.forEach((e,t)=>p.push({name:`textOverlay_${t}.png`,bytes:e}));const l=function(e){const t=String(e??"mp4").toLowerCase();return"mov"===t||"mxf"===t?t:"mp4"}(m.exportSettings?.format),f=a?.length?a:function(e){if(!e?.poster?.useAsVideoCover)return;const t=("string"==typeof e.poster.preview?e.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);return t?Buffer.from(t[1],"base64"):void 0}(m),d=(s,n,a)=>{const p={videoPaths:[s,...e.slice(1).map((e,t)=>a[`video_${t+1}.mp4`])],videoHasAudio:u,audioPaths:o.map((e,t)=>a[`audio_${t}.${O(r[t].type)}`]),overlayPath:i?a["overlay.png"]:void 0,textOverlayPaths:c.map((e,t)=>a[`textOverlay_${t}.png`]).filter(Boolean)};return t(m,p,n)};return{ok:!0,bytes:null==f?await x(e[0],d,l,p,28e4):await E(e[0],d,l,p,f,28e4),contentType:$(l),filename:`edited.${l}`}}catch(e){return(e.message??"").includes("二进制缺失")?b(503,"SERVER_NOT_READY","服务端编码组件未就绪(ffmpeg 缺失),请联系管理员"):b(502,"ENCODE_FAILED","视频处理失败,请重试或换更短的视频")}}}}function R(e){const t=e?.maxBytes??104857600;return{async handle(e,s){if(!/^video\//.test(e.type))return b(415,"BAD_TYPE","只支持视频文件");if(e.bytes.length>t)return b(413,"TOO_LARGE","文件超过 100MB");if(!isFinite(s)||s<0)return b(400,"BAD_TIME","time 参数不合法");try{return{ok:!0,bytes:await x(e.bytes,(e,t)=>o(e,s,t),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}catch(e){return(e.message??"").includes("二进制缺失")?b(503,"SERVER_NOT_READY","服务端编码组件未就绪(ffmpeg 缺失),请联系管理员"):b(502,"EXTRACT_FAILED","封面抽取失败,请重试")}}}}export{T as DEFAULT_LIMITS,_ as composeVideo,R as createPosterHandler,S as createVideoExportHandler,h as extractAudio,v as probeHasAudio,A as probeVideoDuration,x as runVideoEdit};
@@ -0,0 +1 @@
1
+ "use strict";Object.assign(exports,require("../dist/adapters/express.cjs"));
@@ -0,0 +1 @@
1
+ export * from '../dist/adapters/express';
@@ -0,0 +1 @@
1
+ export*from"../dist/adapters/express.js";
package/express/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.assign(exports,require("../dist/adapters/express.cjs"));
1
+ "use strict";Object.assign(exports,require("../dist/adapters/express.cjs"));
package/express/index.js CHANGED
@@ -1 +1 @@
1
- export*from"../dist/adapters/express.js";
1
+ export*from"../dist/adapters/express.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bylqwjc/media-editor-server",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "媒体编辑器服务端:框架无关的视频导出/封面处理器 + Web(Next)/Express 适配器(Node + ffmpeg-static)",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/web/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.assign(exports,require("../dist/adapters/web.cjs"));
1
+ "use strict";Object.assign(exports,require("../dist/adapters/web.cjs"));
package/web/index.js CHANGED
@@ -1 +1 @@
1
- export*from"../dist/adapters/web.js";
1
+ export*from"../dist/adapters/web.js";
@@ -0,0 +1 @@
1
+ "use strict";Object.assign(exports,require("../dist/adapters/web.cjs"));
@@ -0,0 +1 @@
1
+ export * from '../dist/adapters/web';
@@ -0,0 +1 @@
1
+ export*from"../dist/adapters/web.js";