@bylqwjc/media-editor-server 1.0.10

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 (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/dist/adapters/express.cjs +1 -0
  4. package/dist/adapters/express.d.ts +30 -0
  5. package/dist/adapters/express.js +1 -0
  6. package/dist/adapters/web.cjs +1 -0
  7. package/dist/adapters/web.d.ts +15 -0
  8. package/dist/adapters/web.js +1 -0
  9. package/dist/handler-DL4Inp7o.d.ts +47 -0
  10. package/dist/index.cjs +4 -0
  11. package/dist/index.d.ts +59 -0
  12. package/dist/index.js +4 -0
  13. package/node_modules/@media-editor/core/LICENSE +21 -0
  14. package/node_modules/@media-editor/core/README.md +14 -0
  15. package/node_modules/@media-editor/core/dist/browser.cjs +1 -0
  16. package/node_modules/@media-editor/core/dist/browser.d.ts +100 -0
  17. package/node_modules/@media-editor/core/dist/browser.js +3 -0
  18. package/node_modules/@media-editor/core/dist/chunk-MGKYVYOH.js +1 -0
  19. package/node_modules/@media-editor/core/dist/chunk-USY6UDGL.js +1 -0
  20. package/node_modules/@media-editor/core/dist/chunk-XCBM7P7N.js +1 -0
  21. package/node_modules/@media-editor/core/dist/engine.cjs +1 -0
  22. package/node_modules/@media-editor/core/dist/engine.d.ts +359 -0
  23. package/node_modules/@media-editor/core/dist/engine.js +1 -0
  24. package/node_modules/@media-editor/core/dist/filerobot.cjs +1 -0
  25. package/node_modules/@media-editor/core/dist/filerobot.d.ts +88 -0
  26. package/node_modules/@media-editor/core/dist/filerobot.js +1 -0
  27. package/node_modules/@media-editor/core/dist/index.cjs +1 -0
  28. package/node_modules/@media-editor/core/dist/index.d.ts +264 -0
  29. package/node_modules/@media-editor/core/dist/index.js +1 -0
  30. package/node_modules/@media-editor/core/dist/platform-presets-B-o4C6uY.d.ts +80 -0
  31. package/node_modules/@media-editor/core/dist/state-B85vkf7_.d.ts +1027 -0
  32. package/node_modules/@media-editor/core/node_modules/zod/LICENSE +21 -0
  33. package/node_modules/@media-editor/core/node_modules/zod/README.md +208 -0
  34. package/node_modules/@media-editor/core/node_modules/zod/index.cjs +1 -0
  35. package/node_modules/@media-editor/core/node_modules/zod/index.d.cts +4 -0
  36. package/node_modules/@media-editor/core/node_modules/zod/index.js +1 -0
  37. package/node_modules/@media-editor/core/node_modules/zod/package.json +76 -0
  38. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.cjs +1 -0
  39. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.d.cts +164 -0
  40. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.js +1 -0
  41. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.cjs +1 -0
  42. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.d.cts +5 -0
  43. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.js +1 -0
  44. package/node_modules/@media-editor/core/node_modules/zod/v3/external.cjs +1 -0
  45. package/node_modules/@media-editor/core/node_modules/zod/v3/external.d.cts +6 -0
  46. package/node_modules/@media-editor/core/node_modules/zod/v3/external.js +1 -0
  47. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.cjs +1 -0
  48. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.d.cts +8 -0
  49. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.js +0 -0
  50. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.cjs +1 -0
  51. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.d.cts +9 -0
  52. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.js +1 -0
  53. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.cjs +1 -0
  54. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.d.cts +78 -0
  55. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.js +1 -0
  56. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.cjs +1 -0
  57. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.d.cts +8 -0
  58. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.js +0 -0
  59. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.cjs +1 -0
  60. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.d.cts +2 -0
  61. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.js +0 -0
  62. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.cjs +1 -0
  63. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.d.cts +85 -0
  64. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.js +1 -0
  65. package/node_modules/@media-editor/core/node_modules/zod/v3/index.cjs +1 -0
  66. package/node_modules/@media-editor/core/node_modules/zod/v3/index.d.cts +4 -0
  67. package/node_modules/@media-editor/core/node_modules/zod/v3/index.js +1 -0
  68. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.cjs +1 -0
  69. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.d.cts +3 -0
  70. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.js +1 -0
  71. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.cjs +1 -0
  72. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.d.cts +102 -0
  73. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.js +0 -0
  74. package/node_modules/@media-editor/core/node_modules/zod/v3/types.cjs +1 -0
  75. package/node_modules/@media-editor/core/node_modules/zod/v3/types.d.cts +1031 -0
  76. package/node_modules/@media-editor/core/node_modules/zod/v3/types.js +1 -0
  77. package/node_modules/@media-editor/core/package.json +42 -0
  78. package/package.json +43 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 media-editor-sdk contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @media-editor/server
2
+
3
+ Node 侧视频导出和封面抽取处理器。内置 Web 标准适配器和 Express 适配器,依赖 `ffmpeg-static`。
4
+
5
+ ## Next.js App Router
6
+
7
+ ```ts
8
+ import { createVideoExportHandler } from '@media-editor/server';
9
+ import { toWebVideoHandler } from '@media-editor/server/web';
10
+
11
+ export const runtime = 'nodejs';
12
+ export const maxDuration = 300;
13
+
14
+ export const POST = toWebVideoHandler(createVideoExportHandler());
15
+ ```
16
+
17
+ ## Express
18
+
19
+ ```ts
20
+ import express from 'express';
21
+ import multer from 'multer';
22
+ import { createPosterHandler, createVideoExportHandler } from '@media-editor/server';
23
+ import { expressPoster, expressVideoExport } from '@media-editor/server/express';
24
+
25
+ const app = express();
26
+ const upload = multer();
27
+
28
+ app.post('/api/editor/video', upload.any(), expressVideoExport(createVideoExportHandler()));
29
+ app.post('/api/editor/poster', upload.any(), expressPoster(createPosterHandler()));
30
+ ```
31
+
32
+ 接口失败时会返回稳定错误契约:
33
+
34
+ ```json
35
+ { "error": "BAD_REQUEST", "message": "..." }
36
+ ```
@@ -0,0 +1 @@
1
+ "use strict";var f=Object.defineProperty,y=Object.getOwnPropertyDescriptor,c=Object.getOwnPropertyNames,d=Object.prototype.hasOwnProperty,m=(t,e)=>{for(var o in e)f(t,o,{get:e[o],enumerable:!0})},b=(t,e,o,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of c(e))!d.call(t,r)&&r!==o&&f(t,r,{get:()=>e[r],enumerable:!(s=y(e,r))||s.enumerable});return t},_=t=>b(f({},"__esModule",{value:!0}),t),p={};m(p,{expressPoster:()=>g,expressVideoExport:()=>v}),module.exports=_(p);function u(t){return Array.isArray(t.files)?t.files:t.files&&typeof t.files=="object"?Object.values(t.files).flat():[]}function l(t,e){const o=[];for(let s=0;;s++){const r=t.find(n=>n.fieldname===`${e}_${s}`);if(!r)break;o.push({type:r.mimetype,bytes:r.buffer})}return o}function a(t,e){if(e.ok){t.setHeader("Content-Type",e.contentType),t.setHeader("Content-Disposition",`attachment; filename="${e.filename}"`),t.setHeader("Cache-Control","no-store"),t.send(e.bytes);return}t.status(e.status).json({error:e.error,message:e.message})}function v(t){return async(e,o)=>{const s=u(e),r=s.find(i=>i.fieldname==="overlay");if(r&&r.mimetype!=="image/png"){a(o,{ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});return}const n={videos:l(s,"video"),audios:l(s,"audio"),overlay:r?.buffer,editStateRaw:typeof e.body?.editState=="string"?e.body.editState:""};a(o,await t.handle(n))}}function g(t){return async(e,o)=>{const r=u(e).find(i=>i.fieldname==="file"),n=e.body?.time;if(!r||typeof n!="string"){a(o,{ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"});return}a(o,await t.handle({type:r.mimetype,bytes:r.buffer},Number(n)))}}
@@ -0,0 +1,30 @@
1
+ import { P as PosterHandler, V as VideoExportHandler } from '../handler-DL4Inp7o.js';
2
+
3
+ /**
4
+ * Express 适配器。用法:
5
+ * import multer from 'multer';
6
+ * import { createVideoExportHandler } from '@media-editor/server';
7
+ * import { expressVideoExport } from '@media-editor/server/express';
8
+ * app.post('/api/editor/video', multer().any(), expressVideoExport(createVideoExportHandler()));
9
+ * multer().any() 把所有字段放进 req.files(含 fieldname/mimetype/buffer),文本字段进 req.body。
10
+ */
11
+
12
+ interface MulterFile {
13
+ fieldname: string;
14
+ mimetype: string;
15
+ buffer: Buffer;
16
+ }
17
+ interface ReqLike {
18
+ files?: MulterFile[] | Record<string, MulterFile[]>;
19
+ body?: Record<string, unknown>;
20
+ }
21
+ interface ResLike {
22
+ status(code: number): ResLike;
23
+ json(body: unknown): void;
24
+ setHeader(k: string, v: string): void;
25
+ send(body: unknown): void;
26
+ }
27
+ declare function expressVideoExport(handler: VideoExportHandler): (req: ReqLike, res: ResLike) => Promise<void>;
28
+ declare function expressPoster(handler: PosterHandler): (req: ReqLike, res: ResLike) => Promise<void>;
29
+
30
+ export { expressPoster, expressVideoExport };
@@ -0,0 +1 @@
1
+ function u(e){return Array.isArray(e.files)?e.files:e.files&&typeof e.files=="object"?Object.values(e.files).flat():[]}function l(e,t){const o=[];for(let i=0;;i++){const s=e.find(a=>a.fieldname===`${t}_${i}`);if(!s)break;o.push({type:s.mimetype,bytes:s.buffer})}return o}function r(e,t){if(t.ok){e.setHeader("Content-Type",t.contentType),e.setHeader("Content-Disposition",`attachment; filename="${t.filename}"`),e.setHeader("Cache-Control","no-store"),e.send(t.bytes);return}e.status(t.status).json({error:t.error,message:t.message})}function m(e){return async(t,o)=>{const i=u(t),s=i.find(n=>n.fieldname==="overlay"),a=i.find(n=>n.fieldname==="videoCover"),f=l(i,"textOverlay");if(s&&s.mimetype!=="image/png"){r(o,{ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});return}if(f.some(n=>n.type!=="image/png")){r(o,{ok:!1,status:415,error:"BAD_OVERLAY",message:"textOverlay \u5FC5\u987B\u662F PNG"});return}if(a&&!/^image\/(?:png|jpe?g)$/.test(a.mimetype)){r(o,{ok:!1,status:415,error:"BAD_COVER",message:"videoCover must be PNG or JPG"});return}const y={videos:l(i,"video"),audios:l(i,"audio"),overlay:s?.buffer,videoCover:a?.buffer,textOverlays:f.map(n=>n.bytes),editStateRaw:typeof t.body?.editState=="string"?t.body.editState:""};r(o,await e.handle(y))}}function d(e){return async(t,o)=>{const s=u(t).find(f=>f.fieldname==="file"),a=t.body?.time;if(!s||typeof a!="string"){r(o,{ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"});return}r(o,await e.handle({type:s.mimetype,bytes:s.buffer},Number(a)))}}export{d as expressPoster,m as expressVideoExport};
@@ -0,0 +1 @@
1
+ "use strict";var p=Object.defineProperty,w=Object.getOwnPropertyDescriptor,b=Object.getOwnPropertyNames,v=Object.prototype.hasOwnProperty,O=(e,r)=>{for(var t in r)p(e,t,{get:r[t],enumerable:!0})},P=(e,r,t,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of b(r))!v.call(e,o)&&o!==t&&p(e,o,{get:()=>r[o],enumerable:!(a=w(r,o))||a.enumerable});return e},h=e=>P(p({},"__esModule",{value:!0}),e),d={};O(d,{toWebPosterHandler:()=>D,toWebVideoHandler:()=>B}),module.exports=h(d);var g=16;function f(e){return typeof e=="object"&&e!==null&&typeof e.type=="string"&&typeof e.arrayBuffer=="function"}async function c(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 B(e){return async r=>{let t;try{t=await r.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const a=[];for(let n=0;n<g;n++){const i=t.get(`video_${n}`);if(!f(i))break;a.push(await c(i))}const o=[];for(let n=0;n<g;n++){const i=t.get(`audio_${n}`);if(!f(i))break;o.push(await c(i))}const l=t.get("editState"),y=t.get("overlay"),u=f(y)?y:void 0,_=u?Buffer.from(await u.arrayBuffer()):void 0;if(u&&u.type!=="image/png")return s({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});const m={videos:a,audios:o,overlay:_,editStateRaw:typeof l=="string"?l:""};return s(await e.handle(m))}}function D(e){return async r=>{let t;try{t=await r.formData()}catch{return s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const a=t.get("file"),o=t.get("time");return!f(a)||typeof o!="string"?s({ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"}):s(await e.handle(await c(a),Number(o)))}}
@@ -0,0 +1,15 @@
1
+ import { P as PosterHandler, V as VideoExportHandler } from '../handler-DL4Inp7o.js';
2
+
3
+ /**
4
+ * Web 标准适配器(Next.js App Router 路由 / 任何接收 Request 返回 Response 的运行时)。
5
+ * 用法(Next):
6
+ * import { createVideoExportHandler } from '@media-editor/server';
7
+ * import { toWebVideoHandler } from '@media-editor/server/web';
8
+ * export const runtime = 'nodejs'; export const maxDuration = 300;
9
+ * export const POST = toWebVideoHandler(createVideoExportHandler());
10
+ */
11
+
12
+ declare function toWebVideoHandler(handler: VideoExportHandler): (request: Request) => Promise<Response>;
13
+ declare function toWebPosterHandler(handler: PosterHandler): (request: Request) => Promise<Response>;
14
+
15
+ export { toWebPosterHandler, toWebVideoHandler };
@@ -0,0 +1 @@
1
+ var y=16;function s(e){return typeof e=="object"&&e!==null&&typeof e.type=="string"&&typeof e.arrayBuffer=="function"}async function c(e){return{type:e.type,bytes:Buffer.from(await e.arrayBuffer())}}function a(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 l=>{let t;try{t=await l.formData()}catch{return a({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const n=[];for(let r=0;r<y;r++){const o=t.get(`video_${r}`);if(!s(o))break;n.push(await c(o))}const i=[];for(let r=0;r<y;r++){const o=t.get(`audio_${r}`);if(!s(o))break;i.push(await c(o))}const p=t.get("editState"),g=t.get("overlay"),m=t.get("videoCover"),f=s(g)?g:void 0,u=s(m)?m:void 0,v=f?Buffer.from(await f.arrayBuffer()):void 0,B=u?Buffer.from(await u.arrayBuffer()):void 0,d=[];for(let r=0;r<y;r++){const o=t.get(`textOverlay_${r}`);if(!s(o))break;if(o.type!=="image/png")return a({ok:!1,status:415,error:"BAD_OVERLAY",message:"textOverlay \u5FC5\u987B\u662F PNG"});d.push(Buffer.from(await o.arrayBuffer()))}if(f&&f.type!=="image/png")return a({ok:!1,status:415,error:"BAD_OVERLAY",message:"overlay \u5FC5\u987B\u662F PNG"});if(u&&!/^image\/(?:png|jpe?g)$/.test(u.type))return a({ok:!1,status:415,error:"BAD_COVER",message:"videoCover \u5FC5\u987B\u662F PNG \u6216 JPG"});const w={videos:n,audios:i,overlay:v,videoCover:B,textOverlays:d,editStateRaw:typeof p=="string"?p:""};return a(await e.handle(w))}}function F(e){return async l=>{let t;try{t=await l.formData()}catch{return a({ok:!1,status:400,error:"BAD_REQUEST",message:"\u8BF7\u6C42\u4F53\u89E3\u6790\u5931\u8D25"})}const n=t.get("file"),i=t.get("time");return!s(n)||typeof i!="string"?a({ok:!1,status:400,error:"BAD_REQUEST",message:"\u7F3A\u5C11 file \u6216 time"}):a(await e.handle(await c(n),Number(i)))}}export{F as toWebPosterHandler,C as toWebVideoHandler};
@@ -0,0 +1,47 @@
1
+ interface ExportLimits {
2
+ maxVideos: number;
3
+ maxAudios: number;
4
+ maxVideoBytes: number;
5
+ maxTotalVideoBytes: number;
6
+ maxAudioBytes: number;
7
+ maxOverlayBytes: number;
8
+ }
9
+ declare const DEFAULT_LIMITS: ExportLimits;
10
+ /** 一个上传文件的最小抽象(适配器从各自 multipart 解析后喂入) */
11
+ interface UploadFile {
12
+ type: string;
13
+ bytes: Buffer;
14
+ }
15
+ interface ParsedVideoExport {
16
+ videos: UploadFile[];
17
+ audios: UploadFile[];
18
+ overlay?: Buffer;
19
+ editStateRaw: string;
20
+ }
21
+ type ExportOk = {
22
+ ok: true;
23
+ bytes: Buffer;
24
+ contentType: string;
25
+ filename: string;
26
+ };
27
+ type ExportErr = {
28
+ ok: false;
29
+ status: number;
30
+ error: string;
31
+ message: string;
32
+ };
33
+ type ExportResult = ExportOk | ExportErr;
34
+ interface VideoExportHandler {
35
+ handle(parsed: ParsedVideoExport): Promise<ExportResult>;
36
+ }
37
+ declare function createVideoExportHandler(opts?: {
38
+ limits?: Partial<ExportLimits>;
39
+ }): VideoExportHandler;
40
+ interface PosterHandler {
41
+ handle(file: UploadFile, time: number): Promise<ExportResult>;
42
+ }
43
+ declare function createPosterHandler(opts?: {
44
+ maxBytes?: number;
45
+ }): PosterHandler;
46
+
47
+ export { DEFAULT_LIMITS as D, type ExportErr as E, type PosterHandler as P, type UploadFile as U, type VideoExportHandler as V, type ExportLimits as a, type ExportOk as b, type ExportResult as c, type ParsedVideoExport as d, createPosterHandler as e, createVideoExportHandler as f };
package/dist/index.cjs ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";var N=Object.create;var I=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var z=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var K=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of U(t))!J.call(e,o)&&o!==r&&I(e,o,{get:()=>t[o],enumerable:!(i=G(t,o))||i.enumerable});return e};var W=(e,t,r)=>(r=e!=null?N(z(e)):{},K(t||!e||!e.__esModule?I(r,"default",{value:e,enumerable:!0}):r,e));var Q=Object.create,P=Object.defineProperty,X=Object.getOwnPropertyDescriptor,Z=Object.getOwnPropertyNames,ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty,ue=(e,t)=>{for(var r in t)P(e,r,{get:t[r],enumerable:!0})},L=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of Z(t))!te.call(e,o)&&o!==r&&P(e,o,{get:()=>t[o],enumerable:!(i=X(t,o))||i.enumerable});return e},re=(e,t,r)=>(r=e!=null?Q(ee(e)):{},L(t||!e||!e.__esModule?P(r,"default",{value:e,enumerable:!0}):r,e)),oe=e=>L(P({},"__esModule",{value:!0}),e),R={};ue(R,{DEFAULT_LIMITS:()=>H,composeVideo:()=>fe,createPosterHandler:()=>he,createVideoExportHandler:()=>ve,extractAudio:()=>pe,probeHasAudio:()=>$,probeVideoDuration:()=>M,runVideoEdit:()=>V}),module.exports=oe(R);var ie=require("@media-editor/core"),k=require("@media-editor/core"),S=re(require("ffmpeg-static"),1),T=require("child_process"),m=require("fs/promises"),ne=require("fs"),ae=require("os"),d=require("path"),se={};async function ce(){const e=[];S.default&&typeof S.default=="string"&&e.push(S.default);try{const{createRequire:t}=await import("module"),i=t(se.url).resolve("ffmpeg-static/package.json"),o=i.substring(0,i.lastIndexOf("/"));e.push((0,d.join)(o,"ffmpeg"))}catch{}e.push((0,d.join)(process.cwd(),"node_modules","ffmpeg-static","ffmpeg"),(0,d.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,m.access)(t,ne.constants.X_OK),t}catch{}return null}var b;async function O(){return b!==void 0||(b=await ce(),b||console.warn("[ffmpeg-runner] ffmpeg-static \u4E8C\u8FDB\u5236\u672A\u627E\u5230 (\u5C1D\u8BD5\u4E86\u591A\u4E2A fallback \u8DEF\u5F84)")),b}async function x({args:e,timeoutMs:t=18e4}){const r=await O();if(!r)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((i,o)=>{const s=(0,T.spawn)(r,e,{stdio:["ignore","pipe","pipe"]});let n="",f=!1;const a=setTimeout(()=>{f=!0,s.kill("SIGKILL"),o(new Error(`ffmpeg \u8D85\u65F6 (${t}ms)`))},t);s.stderr.on("data",u=>{n+=u.toString(),n.length>8192&&(n=n.slice(-8192))}),s.on("close",u=>{if(clearTimeout(a),f)return;const p=n.slice(-2500);console.log(`[ffmpeg-runner] exit=${u}, stderr tail:
2
+ ${p}
3
+ ---end---`),u===0?i():o(new Error(`ffmpeg \u9000\u51FA\u7801 ${u}: ${p.slice(-800)}`))}),s.on("error",u=>{clearTimeout(a),o(u)})})}async function B(e){const t=await(0,m.mkdtemp)((0,d.join)((0,ae.tmpdir)(),"vtrans-"));try{return await e(t)}finally{(0,m.rm)(t,{recursive:!0,force:!0}).catch(()=>{})}}async function $(e){const t=await O();return t?B(async r=>{const i=(0,d.join)(r,"probe.mp4");return await(0,m.writeFile)(i,e),new Promise(o=>{const s=(0,T.spawn)(t,["-hide_banner","-i",i],{stdio:["ignore","ignore","pipe"]});let n="";const f=setTimeout(()=>{s.kill("SIGKILL"),o(!1)},15e3);s.stderr.on("data",a=>{n+=a.toString(),n.length>16384&&(n=n.slice(-16384))}),s.on("close",()=>{clearTimeout(f),o(/Stream #[^\n]*Audio:/.test(n))}),s.on("error",()=>{clearTimeout(f),o(!1)})})}):!1}async function pe(e){return B(async t=>{const r=(0,d.join)(t,"in.mp4"),i=(0,d.join)(t,"audio.mp3");return await(0,m.writeFile)(r,e),await x({args:["-y","-i",r,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",i],timeoutMs:6e4}),(0,m.readFile)(i)})}var le=["Fontsize=14","PrimaryColour=&H00FFFFFF","OutlineColour=&H00000000","BackColour=&H80000000","BorderStyle=1","Outline=2","Shadow=0","Alignment=2","MarginV=80","Bold=1"].join(",");async function fe(e){const r=(await M(e.videoBytes)).durationSeconds;return B(async i=>{const o=(0,d.join)(i,"in.mp4"),s=(0,d.join)(i,"out.mp4");await(0,m.writeFile)(o,e.videoBytes);const n=["-i",o];let f=-1,a=-1;if(e.newAudioBytes){const g=(0,d.join)(i,"new.mp3");await(0,m.writeFile)(g,e.newAudioBytes),f=(n.length-0)/2,n.push("-i",g)}if(e.bgmAudioBytes){const g=(0,d.join)(i,"bgm.mp3");await(0,m.writeFile)(g,e.bgmAudioBytes),a=n.length/2,n.push("-i",g)}const u=e.srtContent&&e.srtContent.trim().length>0;let p=null;u&&(p=(0,d.join)(i,"subs.srt"),await(0,m.writeFile)(p,e.srtContent));const v=e.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${e.videoBytes.length}B (${r.toFixed(2)}s), newAudio=${e.newAudioBytes?.length??0}B, bgm=${e.bgmAudioBytes?.length??0}B@${v}, srt=${e.srtContent?.length??0}chars`);const y=le.replace(/,/g,"\\,"),h=[];let _,D=!1;u&&p?(h.push(`[0:v]subtitles=${p}:force_style=${y}[v]`),_="[v]",D=!0):_="0:v:0";const A=[];f>=0&&A.push({idx:f,isBgm:!1}),a>=0&&A.push({idx:a,isBgm:!0});let c=null;if(A.length===1)c=`${A[0].idx}:a:0`;else if(A.length>=2){const g=[];for(const w of A)w.isBgm?(h.push(`[${w.idx}:a]volume=${v}[bgm]`),g.push("[bgm]")):g.push(`[${w.idx}:a]`);h.push(`${g.join("")}amix=inputs=${g.length}:duration=first:dropout_transition=0[a]`),c="[a]"}const F=["-y",...n];h.length>0&&F.push("-filter_complex",h.join(";")),F.push("-map",_),c&&F.push("-map",c),D?F.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):F.push("-c:v","copy"),F.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",r.toFixed(3)),F.push(s),await x({args:F,timeoutMs:18e4});const C=c?await O():null;if(C)try{const g=await new Promise(w=>{const E=(0,T.spawn)(C,["-i",s],{stdio:["ignore","pipe","pipe"]});let j="";E.stderr.on("data",Y=>j+=Y.toString()),E.on("close",()=>w(j))});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,m.readFile)(s)})}async function M(e){return B(async t=>{const r=(0,d.join)(t,"in.mp4");await(0,m.writeFile)(r,e);const i=await O();if(!i)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931");return new Promise((o,s)=>{const n=(0,T.spawn)(i,["-i",r],{stdio:["ignore","pipe","pipe"]});let f="";n.stderr.on("data",a=>f+=a.toString()),n.on("close",()=>{const a=f.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!a)return s(new Error("\u65E0\u6CD5\u89E3\u6790\u89C6\u9891\u65F6\u957F"));const u=parseInt(a[1]),p=parseInt(a[2]),v=parseFloat(a[3]);o({durationSeconds:u*3600+p*60+v})}),n.on("error",s)})})}async function V(e,t,r="mp4",i=[],o=24e4){return B(async s=>{const n=(0,d.join)(s,"input.mp4"),f=(0,d.join)(s,`output.${r}`);await(0,m.writeFile)(n,e);const a={};for(const u of i){const p=u.name.replace(/[^a-zA-Z0-9._-]/g,"_"),v=(0,d.join)(s,p);await(0,m.writeFile)(v,u.bytes),a[u.name]=v}return await x({args:t(n,f,a),timeoutMs:o}),(0,m.readFile)(f)})}function de(e){const t=String(e??"").toLowerCase();return t==="mp4"||t==="mov"}function me(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 ge(e,t,r="mp4",i=[],o,s=24e4){return B(async n=>{const f=(0,d.join)(n,"input.mp4"),a=(0,d.join)(n,`output.${r}`),u=(0,d.join)(n,"video-cover.png"),p=(0,d.join)(n,`output-with-cover.${r}`);await(0,m.writeFile)(f,e);const v={};for(const y of i){const h=y.name.replace(/[^a-zA-Z0-9._-]/g,"_"),_=(0,d.join)(n,h);await(0,m.writeFile)(_,y.bytes),v[y.name]=_}return await x({args:t(f,a,v),timeoutMs:s}),!de(r)||!o?.length?(0,m.readFile)(a):(await(0,m.writeFile)(u,o),await x({args:me(a,u,p),timeoutMs:s}),(0,m.readFile)(p))})}var H={maxVideos:6,maxAudios:3,maxVideoBytes:100*1024*1024,maxTotalVideoBytes:300*1024*1024,maxAudioBytes:30*1024*1024,maxOverlayBytes:20*1024*1024},l=(e,t,r)=>({ok:!1,status:e,error:t,message:r});function q(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 Fe(e){if(!e?.poster?.useAsVideoCover)return;const r=(typeof e.poster.preview=="string"?e.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);if(r)return Buffer.from(r[1],"base64")}function ve(e){const t={...H,...e?.limits};return{async handle(r){const{videos:i,audios:o,overlay:s,videoCover:n,editStateRaw:f}=r;if(i.length>t.maxVideos)return l(413,"TOO_MANY",`\u89C6\u9891\u6570\u8D85\u8FC7 ${t.maxVideos}`);for(let u=0;u<i.length;u++){if(!/^video\//.test(i[u].type))return l(415,"BAD_TYPE",`video_${u} \u4E0D\u662F\u89C6\u9891\u6587\u4EF6`);if(i[u].bytes.length>t.maxVideoBytes)return l(413,"TOO_LARGE",`\u89C6\u9891 ${u+1} \u8D85\u8FC7 100MB`)}if(!i.length)return l(400,"BAD_REQUEST","\u7F3A\u5C11\u89C6\u9891\u6587\u4EF6(video_0)");if(i.reduce((u,p)=>u+p.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(o.length>t.maxAudios)return l(413,"TOO_MANY",`\u97F3\u9891\u6570\u8D85\u8FC7 ${t.maxAudios}`);for(let u=0;u<o.length;u++){const p=/^audio\//.test(o[u].type),v=/^video\//.test(o[u].type);if(!p&&!v)return l(415,"BAD_TYPE",`audio_${u} \u4E0D\u662F\u97F3\u9891\u6216\u89C6\u9891\u6587\u4EF6`);if(o[u].bytes.length>(v?t.maxVideoBytes:t.maxAudioBytes))return l(413,"TOO_LARGE",`\u97F3\u9891 ${u+1} \u8D85\u8FC7 ${v?"100MB":"30MB"}`)}if(typeof f!="string")return l(400,"BAD_REQUEST","\u7F3A\u5C11 editState");if(s&&s.length>t.maxOverlayBytes)return l(413,"OVERLAY_TOO_LARGE","overlay \u8FC7\u5927");if(n&&n.length>t.maxOverlayBytes)return l(413,"COVER_TOO_LARGE","videoCover \u8FC7\u5927");let a;try{a=ie.VideoEditState.parse(JSON.parse(f))}catch{return l(400,"BAD_STATE","\u7F16\u8F91\u53C2\u6570\u4E0D\u5408\u6CD5")}if(a.clips.some(u=>u.srcIdx>=i.length))return l(400,"BAD_STATE","clips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u89C6\u9891\u6570");if((a.audioClips??[]).some(u=>u.srcIdx>=o.length))return l(400,"BAD_STATE","audioClips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u97F3\u9891\u6570");try{const u=i.map(c=>c.bytes),p=o.map(c=>c.bytes),v=[...new Set((a.audioClips??[]).map(c=>c.srcIdx))];for(const c of v)if(/^video\//.test(o[c].type)&&!await $(p[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 y=i.map(()=>!1);if(a.keepAudio){const c=[...new Set(a.clips.map(F=>F.srcIdx))];await Promise.all(c.map(async F=>{y[F]=await $(u[F])})),!y.some(Boolean)&&!(a.audioClips??[]).length&&(a={...a,keepAudio:!1})}const h=[];for(let c=1;c<u.length;c++)h.push({name:`video_${c}.mp4`,bytes:u[c]});p.forEach((c,F)=>h.push({name:`audio_${F}.${q(o[F].type)}`,bytes:c})),s&&h.push({name:"overlay.png",bytes:s});const _=n?.length?n:Fe(a),D=(c,F,C)=>{const g={videoPaths:[c,...u.slice(1).map((w,E)=>C[`video_${E+1}.mp4`])],videoHasAudio:y,audioPaths:p.map((w,E)=>C[`audio_${E}.${q(o[E].type)}`]),overlayPath:s?C["overlay.png"]:void 0};return(0,k.buildFfmpegArgs)(a,g,F)};return{ok:!0,bytes:_==null?await V(u[0],D,"mp4",h,28e4):await ge(u[0],D,"mp4",h,_,28e4),contentType:"video/mp4",filename:"edited.mp4"}}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 he(e){const t=e?.maxBytes??104857600;return{async handle(r,i){if(!/^video\//.test(r.type))return l(415,"BAD_TYPE","\u53EA\u652F\u6301\u89C6\u9891\u6587\u4EF6");if(r.bytes.length>t)return l(413,"TOO_LARGE","\u6587\u4EF6\u8D85\u8FC7 100MB");if(!isFinite(i)||i<0)return l(400,"BAD_TIME","time \u53C2\u6570\u4E0D\u5408\u6CD5");try{return{ok:!0,bytes:await V(r.bytes,(s,n)=>(0,k.buildPosterArgs)(s,i,n),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}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,"EXTRACT_FAILED","\u5C01\u9762\u62BD\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5")}}}}
@@ -0,0 +1,59 @@
1
+ export { D as DEFAULT_LIMITS, E as ExportErr, a as ExportLimits, b as ExportOk, c as ExportResult, d as ParsedVideoExport, P as PosterHandler, U as UploadFile, V as VideoExportHandler, e as createPosterHandler, f as createVideoExportHandler } from './handler-DL4Inp7o.js';
2
+
3
+ /**
4
+ * ffmpeg-runner: 视频/音频处理工具
5
+ *
6
+ * 封装 ffmpeg-static 二进制 + child_process spawn,提供:
7
+ * - extractAudio(): 从视频抽 mp3 (16kHz mono,供 Whisper ASR)
8
+ * - composeReplaceAudio(): 用新音轨替换视频原音轨
9
+ * - composeBurnSubtitles(): 烧录 .srt 字幕到视频
10
+ *
11
+ * MVP V0:
12
+ * - 仅本地 Node 环境 (next dev / vercel functions if binary fits 50MB limit)
13
+ * - 失败 → 抛错(含 stderr 末尾 500 字),pipeline 捕获 → task.status='failed'
14
+ *
15
+ * V1 升级方向:
16
+ * - 部署到独立 worker (Docker + 真 ffmpeg) — 摆脱 50MB 函数包限制
17
+ * - 长视频 → 分片并发
18
+ */
19
+ /**
20
+ * 探测视频是否含音轨:`ffmpeg -i`(无输出文件)必然非零退出,但 stderr 会列出全部流,
21
+ * 只看有没有 "Audio:" 流行。多段导出的 [0:a]atrim 滤镜链在无音轨输入上会直接编码失败,
22
+ * 调用方据此降级 keepAudio —— 用户上传无声视频也能切段/重排/复制导出。
23
+ */
24
+ declare function probeHasAudio(videoBytes: Buffer): Promise<boolean>;
25
+ /**
26
+ * 从视频抽出音轨,16kHz 单声道 mp3 (Whisper 友好格式)
27
+ */
28
+ declare function extractAudio(videoBytes: Buffer): Promise<Buffer>;
29
+ interface ComposeOptions {
30
+ videoBytes: Buffer;
31
+ /** 新音轨字节 (TTS/配音, mp3/wav/aac) — 视频翻译用;视频生成/爆款复刻无此项 */
32
+ newAudioBytes?: Buffer;
33
+ /** 用户上传 BGM (mp3/wav/aac) — 与 newAudioBytes 混音,无新音轨则当主音轨 */
34
+ bgmAudioBytes?: Buffer;
35
+ /** BGM 音量 (0-1),默认 0.18 (垫在配音下面) */
36
+ bgmVolume?: number;
37
+ /** SRT 字幕内容 (空字符串 = 不烧字幕) */
38
+ srtContent?: string;
39
+ }
40
+ declare function composeVideo(opts: ComposeOptions): Promise<Buffer>;
41
+ interface VideoProbe {
42
+ durationSeconds: number;
43
+ }
44
+ declare function probeVideoDuration(videoBytes: Buffer): Promise<VideoProbe>;
45
+ /**
46
+ * 通用视频编辑:写入入字节 → 跑给定 ffmpeg 参数(参数里的 input/output 用占位名)→ 读出产物。
47
+ * 复用模块内的 withTempDir/runFfmpeg;writeFile/readFile/join 已在文件顶部导入。
48
+ * @param argsFor buildFfmpegArgs(state, inputPath, outputPath) 这样的工厂
49
+ */
50
+ declare function runVideoEdit(inputBytes: Buffer, argsFor: (inputPath: string, outputPath: string, extraPaths: Record<string, string>) => string[], outExt?: string,
51
+ /** 额外输入文件(其余视频源/音乐/overlay PNG):写进同一临时目录,路径经 extraPaths 传回 argsFor */
52
+ extraFiles?: Array<{
53
+ name: string;
54
+ bytes: Buffer;
55
+ }>,
56
+ /** 多源 concat 可能更慢,调用方可放宽(默认 240s 不变) */
57
+ timeoutMs?: number): Promise<Buffer>;
58
+
59
+ export { type ComposeOptions, type VideoProbe, composeVideo, extractAudio, probeHasAudio, probeVideoDuration, runVideoEdit };
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import{VideoEditState as M}from"@media-editor/core";import{buildFfmpegArgs as G,buildPosterArgs as H}from"@media-editor/core";import V from"ffmpeg-static";import{spawn as $}from"child_process";import{writeFile as h,readFile as b,mkdtemp as N,rm as j,access as z}from"fs/promises";import{constants as U}from"fs";import{tmpdir as q}from"os";import{join as d}from"path";async function K(){const e=[];V&&typeof V=="string"&&e.push(V);try{const{createRequire:t}=await import("module"),r=t(import.meta.url).resolve("ffmpeg-static/package.json"),i=r.substring(0,r.lastIndexOf("/"));e.push(d(i,"ffmpeg"))}catch{}e.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 t of e)if(t&&!t.startsWith("/ROOT/"))try{return await z(t,U.X_OK),t}catch{}return null}var T;async function S(){return T!==void 0||(T=await K(),T||console.warn("[ffmpeg-runner] ffmpeg-static \u4E8C\u8FDB\u5236\u672A\u627E\u5230 (\u5C1D\u8BD5\u4E86\u591A\u4E2A fallback \u8DEF\u5F84)")),T}async function P({args:e,timeoutMs:t=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(e)),new Promise((r,i)=>{const s=$(o,e,{stdio:["ignore","pipe","pipe"]});let n="",l=!1;const f=setTimeout(()=>{l=!0,s.kill("SIGKILL"),i(new Error(`ffmpeg \u8D85\u65F6 (${t}ms)`))},t);s.stderr.on("data",a=>{n+=a.toString(),n.length>8192&&(n=n.slice(-8192))}),s.on("close",a=>{if(clearTimeout(f),l)return;const u=n.slice(-2500);console.log(`[ffmpeg-runner] exit=${a}, stderr tail:
2
+ ${u}
3
+ ---end---`),a===0?r():i(new Error(`ffmpeg \u9000\u51FA\u7801 ${a}: ${u.slice(-800)}`))}),s.on("error",a=>{clearTimeout(f),i(a)})})}async function _(e){const t=await N(d(q(),"vtrans-"));try{return await e(t)}finally{j(t,{recursive:!0,force:!0}).catch(()=>{})}}async function R(e){const t=await S();return t?_(async o=>{const r=d(o,"probe.mp4");return await h(r,e),new Promise(i=>{const s=$(t,["-hide_banner","-i",r],{stdio:["ignore","ignore","pipe"]});let n="";const l=setTimeout(()=>{s.kill("SIGKILL"),i(!1)},15e3);s.stderr.on("data",f=>{n+=f.toString(),n.length>16384&&(n=n.slice(-16384))}),s.on("close",()=>{clearTimeout(l),i(/Stream #[^\n]*Audio:/.test(n))}),s.on("error",()=>{clearTimeout(l),i(!1)})})}):!1}async function W(e){return _(async t=>{const o=d(t,"in.mp4"),r=d(t,"audio.mp3");return await h(o,e),await P({args:["-y","-i",o,"-vn","-acodec","libmp3lame","-ar","16000","-ac","1","-b:a","64k",r],timeoutMs:6e4}),b(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(e){const o=(await L(e.videoBytes)).durationSeconds;return _(async r=>{const i=d(r,"in.mp4"),s=d(r,"out.mp4");await h(i,e.videoBytes);const n=["-i",i];let l=-1,f=-1;if(e.newAudioBytes){const c=d(r,"new.mp3");await h(c,e.newAudioBytes),l=(n.length-0)/2,n.push("-i",c)}if(e.bgmAudioBytes){const c=d(r,"bgm.mp3");await h(c,e.bgmAudioBytes),f=n.length/2,n.push("-i",c)}const a=e.srtContent&&e.srtContent.trim().length>0;let u=null;a&&(u=d(r,"subs.srt"),await h(u,e.srtContent));const g=e.bgmVolume??.18;console.log(`[ffmpeg-runner] composeVideo: video=${e.videoBytes.length}B (${o.toFixed(2)}s), newAudio=${e.newAudioBytes?.length??0}B, bgm=${e.bgmAudioBytes?.length??0}B@${g}, srt=${e.srtContent?.length??0}chars`);const y=J.replace(/,/g,"\\,"),v=[];let F,D=!1;a&&u?(v.push(`[0:v]subtitles=${u}:force_style=${y}[v]`),F="[v]",D=!0):F="0:v:0";const E=[];l>=0&&E.push({idx:l,isBgm:!1}),f>=0&&E.push({idx:f,isBgm:!0});let w=null;if(E.length===1)w=`${E[0].idx}:a:0`;else if(E.length>=2){const c=[];for(const A of E)A.isBgm?(v.push(`[${A.idx}:a]volume=${g}[bgm]`),c.push("[bgm]")):c.push(`[${A.idx}:a]`);v.push(`${c.join("")}amix=inputs=${c.length}:duration=first:dropout_transition=0[a]`),w="[a]"}const C=["-y",...n];v.length>0&&C.push("-filter_complex",v.join(";")),C.push("-map",F),w&&C.push("-map",w),D?C.push("-c:v","libx264","-preset","fast","-crf","22","-pix_fmt","yuv420p"):C.push("-c:v","copy"),C.push("-c:a","aac","-b:a","128k","-ar","44100","-ac","2","-movflags","+faststart","-t",o.toFixed(3)),C.push(s),await P({args:C,timeoutMs:18e4});const p=w?await S():null;if(p)try{const c=await new Promise(A=>{const O=$(p,["-i",s],{stdio:["ignore","pipe","pipe"]});let x="";O.stderr.on("data",B=>x+=B.toString()),O.on("close",()=>A(x))});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 b(s)})}async function L(e){return _(async t=>{const o=d(t,"in.mp4");await h(o,e);const r=await S();if(!r)throw new Error("ffmpeg-static \u4E8C\u8FDB\u5236\u7F3A\u5931");return new Promise((i,s)=>{const n=$(r,["-i",o],{stdio:["ignore","pipe","pipe"]});let l="";n.stderr.on("data",f=>l+=f.toString()),n.on("close",()=>{const f=l.match(/Duration:\s*(\d+):(\d+):(\d+(?:\.\d+)?)/);if(!f)return s(new Error("\u65E0\u6CD5\u89E3\u6790\u89C6\u9891\u65F6\u957F"));const a=parseInt(f[1]),u=parseInt(f[2]),g=parseFloat(f[3]);i({durationSeconds:a*3600+u*60+g})}),n.on("error",s)})})}async function I(e,t,o="mp4",r=[],i=24e4){return _(async s=>{const n=d(s,"input.mp4"),l=d(s,`output.${o}`);await h(n,e);const f={};for(const a of r){const u=a.name.replace(/[^a-zA-Z0-9._-]/g,"_"),g=d(s,u);await h(g,a.bytes),f[a.name]=g}return await P({args:t(n,l,f),timeoutMs:i}),b(l)})}function X(e){const t=String(e??"").toLowerCase();return t==="mp4"||t==="mov"}function Z(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 ee(e,t,o="mp4",r=[],i,s=24e4){return _(async n=>{const l=d(n,"input.mp4"),f=d(n,`output.${o}`),a=d(n,"video-cover.png"),u=d(n,`output-with-cover.${o}`);await h(l,e);const g={};for(const y of r){const v=y.name.replace(/[^a-zA-Z0-9._-]/g,"_"),F=d(n,v);await h(F,y.bytes),g[y.name]=F}return await P({args:t(l,f,g),timeoutMs:s}),!X(o)||!i?.length?b(f):(await h(a,i),await P({args:Z(f,a,u),timeoutMs:s}),b(u))})}var k={maxVideos:6,maxAudios:3,maxVideoBytes:100*1024*1024,maxTotalVideoBytes:300*1024*1024,maxAudioBytes:30*1024*1024,maxOverlayBytes:20*1024*1024},m=(e,t,o)=>({ok:!1,status:e,error:t,message:o});function Y(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 te(e){const t=String(e??"mp4").toLowerCase();return t==="mov"||t==="mxf"?t:"mp4"}function ue(e){return e==="mov"?"video/quicktime":e==="mxf"?"application/mxf":"video/mp4"}function re(e){if(!e?.poster?.useAsVideoCover)return;const o=(typeof e.poster.preview=="string"?e.poster.preview:"").match(/^data:image\/(?:png|jpe?g);base64,([a-z0-9+/=]+)$/i);if(o)return Buffer.from(o[1],"base64")}function ne(e){const t={...k,...e?.limits};return{async handle(o){const{videos:r,audios:i,overlay:s,videoCover:n,textOverlays:l=[],editStateRaw:f}=o;if(r.length>t.maxVideos)return m(413,"TOO_MANY",`\u89C6\u9891\u6570\u8D85\u8FC7 ${t.maxVideos}`);for(let u=0;u<r.length;u++){if(!/^video\//.test(r[u].type))return m(415,"BAD_TYPE",`video_${u} \u4E0D\u662F\u89C6\u9891\u6587\u4EF6`);if(r[u].bytes.length>t.maxVideoBytes)return m(413,"TOO_LARGE",`\u89C6\u9891 ${u+1} \u8D85\u8FC7 100MB`)}if(!r.length)return m(400,"BAD_REQUEST","\u7F3A\u5C11\u89C6\u9891\u6587\u4EF6(video_0)");if(r.reduce((u,g)=>u+g.bytes.length,0)>t.maxTotalVideoBytes)return m(413,"TOO_LARGE","\u89C6\u9891\u603B\u5927\u5C0F\u8D85\u8FC7 300MB,\u8BF7\u51CF\u5C11\u7D20\u6750\u6216\u538B\u7F29");if(i.length>t.maxAudios)return m(413,"TOO_MANY",`\u97F3\u9891\u6570\u8D85\u8FC7 ${t.maxAudios}`);for(let u=0;u<i.length;u++){const g=/^audio\//.test(i[u].type),y=/^video\//.test(i[u].type);if(!g&&!y)return m(415,"BAD_TYPE",`audio_${u} \u4E0D\u662F\u97F3\u9891\u6216\u89C6\u9891\u6587\u4EF6`);if(i[u].bytes.length>(y?t.maxVideoBytes:t.maxAudioBytes))return m(413,"TOO_LARGE",`\u97F3\u9891 ${u+1} \u8D85\u8FC7 ${y?"100MB":"30MB"}`)}if(typeof f!="string")return m(400,"BAD_REQUEST","\u7F3A\u5C11 editState");if(s&&s.length>t.maxOverlayBytes)return m(413,"OVERLAY_TOO_LARGE","overlay \u8FC7\u5927");if(n&&n.length>t.maxOverlayBytes)return m(413,"COVER_TOO_LARGE","videoCover \u8FC7\u5927");if(l.some(u=>u.length>t.maxOverlayBytes))return m(413,"OVERLAY_TOO_LARGE","textOverlay \u8FC7\u5927");let a;try{a=M.parse(JSON.parse(f))}catch{return m(400,"BAD_STATE","\u7F16\u8F91\u53C2\u6570\u4E0D\u5408\u6CD5")}if(a.clips.some(u=>u.srcIdx>=r.length))return m(400,"BAD_STATE","clips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u89C6\u9891\u6570");if((a.audioClips??[]).some(u=>u.srcIdx>=i.length))return m(400,"BAD_STATE","audioClips.srcIdx \u8D85\u51FA\u4E0A\u4F20\u97F3\u9891\u6570");try{const u=r.map(p=>p.bytes),g=i.map(p=>p.bytes),y=[...new Set((a.audioClips??[]).map(p=>p.srcIdx))];for(const p of y)if(/^video\//.test(i[p].type)&&!await R(g[p]))return m(400,"BAD_TYPE",`\u97F3\u9891 ${p+1} \u662F\u89C6\u9891\u6587\u4EF6\u4F46\u6CA1\u6709\u97F3\u8F68,\u65E0\u6CD5\u63D0\u53D6\u58F0\u97F3`);const v=r.map(()=>!1);if(a.keepAudio){const p=[...new Set(a.clips.map(c=>c.srcIdx))];await Promise.all(p.map(async c=>{v[c]=await R(u[c])})),!v.some(Boolean)&&!(a.audioClips??[]).length&&(a={...a,keepAudio:!1})}const F=[];for(let p=1;p<u.length;p++)F.push({name:`video_${p}.mp4`,bytes:u[p]});g.forEach((p,c)=>F.push({name:`audio_${c}.${Y(i[c].type)}`,bytes:p})),s&&F.push({name:"overlay.png",bytes:s}),l.forEach((p,c)=>F.push({name:`textOverlay_${c}.png`,bytes:p}));const D=te(a.exportSettings?.format),E=n?.length?n:re(a),w=(p,c,A)=>{const O={videoPaths:[p,...u.slice(1).map((x,B)=>A[`video_${B+1}.mp4`])],videoHasAudio:v,audioPaths:g.map((x,B)=>A[`audio_${B}.${Y(i[B].type)}`]),overlayPath:s?A["overlay.png"]:void 0,textOverlayPaths:l.map((x,B)=>A[`textOverlay_${B}.png`]).filter(Boolean)};return G(a,O,c)};return{ok:!0,bytes:E==null?await I(u[0],w,D,F,28e4):await ee(u[0],w,D,F,E,28e4),contentType:ue(D),filename:`edited.${D}`}}catch(u){return(u.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?m(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"):m(502,"ENCODE_FAILED","\u89C6\u9891\u5904\u7406\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u6216\u6362\u66F4\u77ED\u7684\u89C6\u9891")}}}}function oe(e){const t=e?.maxBytes??104857600;return{async handle(o,r){if(!/^video\//.test(o.type))return m(415,"BAD_TYPE","\u53EA\u652F\u6301\u89C6\u9891\u6587\u4EF6");if(o.bytes.length>t)return m(413,"TOO_LARGE","\u6587\u4EF6\u8D85\u8FC7 100MB");if(!isFinite(r)||r<0)return m(400,"BAD_TIME","time \u53C2\u6570\u4E0D\u5408\u6CD5");try{return{ok:!0,bytes:await I(o.bytes,(s,n)=>H(s,r,n),"jpg"),contentType:"image/jpeg",filename:"poster.jpg"}}catch(i){return(i.message??"").includes("\u4E8C\u8FDB\u5236\u7F3A\u5931")?m(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"):m(502,"EXTRACT_FAILED","\u5C01\u9762\u62BD\u53D6\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5")}}}}export{k as DEFAULT_LIMITS,Q as composeVideo,oe as createPosterHandler,ne as createVideoExportHandler,W as extractAudio,R as probeHasAudio,L as probeVideoDuration,I as runVideoEdit};
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 media-editor-sdk contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ # @media-editor/core
2
+
3
+ 框架无关核心包。包含视频编辑状态、时间轴、导出参数、滤镜、平台比例、图片编辑器配置工厂和浏览器 canvas 工具。
4
+
5
+ ## 子路径
6
+
7
+ ```ts
8
+ import { defaultVideoEditState } from '@media-editor/core';
9
+ import { VideoEditorEngine } from '@media-editor/core/engine';
10
+ import { buildVideoExportFormData } from '@media-editor/core/browser';
11
+ import { createImageEditorConfig } from '@media-editor/core/filerobot';
12
+ ```
13
+
14
+ `@media-editor/core` 不依赖 React 或 Vue,适合服务端和自定义 UI 复用。
@@ -0,0 +1 @@
1
+ "use strict";var v=Math.PI/180;function y(e,t,a){e.strokeStyle=t,e.lineWidth=a,e.lineCap="round",e.lineJoin="round"}function j(e,t,a,n,r,i){const o=Math.atan2(r-a,n-t),c=Math.max(12,i*3.5);e.beginPath(),e.moveTo(n,r),e.lineTo(n-c*Math.cos(o-Math.PI/7),r-c*Math.sin(o-Math.PI/7)),e.moveTo(n,r),e.lineTo(n-c*Math.cos(o+Math.PI/7),r-c*Math.sin(o+Math.PI/7)),e.stroke()}function b(e){if(!Number.isFinite(e))return 0;let t=e%360;return t>180&&(t-=360),t<-180&&(t+=360),Math.abs(t)<.001?0:t}function g(e){return b(e.rotation??0)}function S(e){switch(e.type){case"pen":{let t=1/0,a=1/0,n=-1/0,r=-1/0;for(let i=0;i<e.points.length;i+=2)t=Math.min(t,e.points[i]),n=Math.max(n,e.points[i]),a=Math.min(a,e.points[i+1]),r=Math.max(r,e.points[i+1]);return{x:t,y:a,w:n-t,h:r-a}}case"line":case"arrow":return{x:Math.min(e.x1,e.x2),y:Math.min(e.y1,e.y2),w:Math.abs(e.x2-e.x1),h:Math.abs(e.y2-e.y1)};case"rect":case"ellipse":case"sticker":return{x:e.x,y:e.y,w:e.w,h:e.h};case"text":return{x:e.x,y:e.y,w:e.text.length*e.fontSize*.6,h:e.fontSize*1.2}}}function M(e){const t=S(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function A(e,t,a,n,r){const i=r*v,o=Math.cos(i),c=Math.sin(i),h=e-a,s=t-n;return{x:a+h*o-s*c,y:n+h*c+s*o}}function F(e,t,a,n,r){return{x:a+(e-a)*r,y:n+(t-n)*r}}function T(e,t,a){const n=g(t);if(n){const r=M(t);e.save(),e.translate(r.x,r.y),e.rotate(n*v),e.translate(-r.x,-r.y),O(e,t,a),e.restore();return}O(e,t,a)}function O(e,t,a){switch(t.type){case"pen":{y(e,t.color,t.width),e.beginPath(),e.moveTo(t.points[0],t.points[1]);for(let n=2;n<t.points.length;n+=2)e.lineTo(t.points[n],t.points[n+1]);e.stroke();break}case"line":case"arrow":{y(e,t.color,t.width),e.beginPath(),e.moveTo(t.x1,t.y1),e.lineTo(t.x2,t.y2),e.stroke(),t.type==="arrow"&&j(e,t.x1,t.y1,t.x2,t.y2,t.width);break}case"rect":{y(e,t.color,t.width),e.strokeRect(t.x,t.y,t.w,t.h);break}case"ellipse":{y(e,t.color,t.width),e.beginPath(),e.ellipse(t.x+t.w/2,t.y+t.h/2,Math.abs(t.w/2),Math.abs(t.h/2),0,0,Math.PI*2),e.stroke();break}case"text":{e.fillStyle=t.color,e.font=`bold ${t.fontSize}px -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif`,e.textBaseline="top",e.strokeStyle="rgba(0,0,0,0.45)",e.lineWidth=Math.max(2,t.fontSize/16),e.lineJoin="round",e.strokeText(t.text,t.x,t.y),e.fillText(t.text,t.x,t.y);break}case"sticker":{if(t.emoji)e.font=`${Math.min(t.w,t.h)}px -apple-system, "Apple Color Emoji", "Segoe UI Emoji", sans-serif`,e.textBaseline="top",e.fillText(t.emoji,t.x,t.y);else if(t.src){const n=a?.get(t.src);n&&e.drawImage(n,t.x,t.y,t.w,t.h)}break}}}function x(e,t,a){for(const n of t)T(e,n,a)}async function P(e){const t=new Map,a=[...new Set(e.filter(n=>n.type==="sticker"&&n.src).map(n=>n.src))];return await Promise.all(a.map(n=>new Promise(r=>{const i=new Image;i.onload=()=>{t.set(n,i),r()},i.onerror=()=>r(),i.src=n}))),t}async function E(e,t,a){if(!e?.length)return null;const n=document.createElement("canvas");n.width=t,n.height=a;const r=n.getContext("2d");if(!r)return null;const i=await P(e);return x(r,e,i),new Promise(o=>n.toBlob(c=>o(c),"image/png"))}function $(e,t,a,n=12){for(let r=e.length-1;r>=0;r--){const i=e[r];if(D(i,t,a,n))return r}return-1}function V(e,t,a,n,r){return Math.abs(e-a)<=r&&Math.abs(t-n)<=r}function C(e,t,a,n,r,i,o){const c=r-a,h=i-n,s=c*c+h*h||1,u=Math.max(0,Math.min(1,((e-a)*c+(t-n)*h)/s)),l=a+u*c,p=n+u*h;return(e-l)**2+(t-p)**2<=o*o}function D(e,t,a,n){const r=g(e);if(r){const i=M(e),o=A(t,a,i.x,i.y,-r);return k(e,o.x,o.y,n)}return k(e,t,a,n)}function k(e,t,a,n){switch(e.type){case"pen":{for(let r=0;r+3<e.points.length;r+=2)if(C(t,a,e.points[r],e.points[r+1],e.points[r+2],e.points[r+3],n+e.width/2))return!0;return!1}case"line":case"arrow":return C(t,a,e.x1,e.y1,e.x2,e.y2,n+e.width/2);case"rect":case"ellipse":return t>=e.x-n&&t<=e.x+e.w+n&&a>=e.y-n&&a<=e.y+e.h+n;case"text":return t>=e.x-n&&t<=e.x+e.text.length*e.fontSize*.6+n&&a>=e.y-n&&a<=e.y+e.fontSize+n;case"sticker":return V(t,a,e.x+e.w/2,e.y+e.h/2,Math.max(e.w,e.h)/2+n)}}function _(e,t,a){const n=Math.max(8,a);if(!(e>0)||!(t>0))return{w:n,h:n};const r=n/Math.max(e,t);return{w:Math.max(8,Math.round(e*r)),h:Math.max(8,Math.round(t*r))}}function N(e,t){const a=Math.max(.05,t),n=M(e);switch(e.type){case"pen":return{...e,points:e.points.map((r,i)=>i%2===0?n.x+(r-n.x)*a:n.y+(r-n.y)*a)};case"line":case"arrow":{const r=F(e.x1,e.y1,n.x,n.y,a),i=F(e.x2,e.y2,n.x,n.y,a);return{...e,x1:r.x,y1:r.y,x2:i.x,y2:i.y}}case"rect":case"ellipse":case"sticker":return{...e,w:Math.max(8,e.w*a),h:Math.max(8,e.h*a)};case"text":return{...e,fontSize:Math.min(512,Math.max(8,e.fontSize*a))};default:return e}}function U(e,t){return{...e,rotation:b(t)}}function Y(e,t,a){switch(e.type){case"pen":{const n=e.points.map((r,i)=>i%2===0?r+t:r+a);return{...e,points:n}}case"line":case"arrow":return{...e,x1:e.x1+t,y1:e.y1+a,x2:e.x2+t,y2:e.y2+a};case"rect":case"ellipse":case"sticker":return{...e,x:e.x+t,y:e.y+a};case"text":return{...e,x:e.x+t,y:e.y+a}}}var I=Math.PI/180;function B(e,t,a){const n=J(a);if(n===0||n===180)return{w:e,h:t};if(n===90||n===270)return{w:t,h:e};const r=n*I;return{w:Math.round(Math.abs(e*Math.cos(r))+Math.abs(t*Math.sin(r))),h:Math.round(Math.abs(e*Math.sin(r))+Math.abs(t*Math.cos(r)))}}function J(e){return(e%360+360)%360}function f(e){const t=Math.round(e);return t-t%2}function z(e,t){let a=e.w,n=a/t;return n>e.h&&(n=e.h,a=n*t),{x:Math.round((e.w-a)/2),y:Math.round((e.h-n)/2),width:Math.round(a),height:Math.round(n)}}function L(e,t,a){const n={x:0,y:0,width:e.width,height:e.height},r={x:0,y:0,width:t.w,height:t.h};return a==="cover"?{src:z({w:e.width,h:e.height},t.w/t.h),dst:r}:a==="contain"?{src:n,dst:z({w:t.w,h:t.h},e.width/e.height)}:{src:n,dst:r}}function R(e,t){if(t.scale)return{w:f(t.scale.width),h:f(t.scale.height)};if(t.crop)return{w:f(t.crop.width),h:f(t.crop.height)};const a=B(e.w,e.h,t.rotation);return{w:f(a.w),h:f(a.h)}}function X(e){const t=String(e??"").match(/^data:(image\/(?:png|jpe?g));base64,([a-z0-9+/=]+)$/i);if(!t)return null;const a=atob(t[2]),n=new Uint8Array(a.length);for(let r=0;r<a.length;r++)n[r]=a.charCodeAt(r);return new Blob([n],{type:t[1].toLowerCase()})}async function q(e,t,a=[]){const n=e.getExportPlan(),r=new FormData;n.videoSrcOrder.forEach((s,u)=>{const l=t[s];l&&r.append(`video_${u}`,l,l.name||`video_${u}.mp4`)}),n.audioSrcOrder.forEach((s,u)=>{const l=a[s];l&&r.append(`audio_${u}`,l,l.name||`audio_${u}`)});const i=R(n.state.canvas,n.state),o=await E(n.state.overlays,i.w,i.h);o&&r.append("overlay",o,"overlay.png");const c=n.state.poster?.useAsVideoCover?X(n.state.poster.preview):null;c&&r.append("videoCover",c,"video-cover.png");const h=n.state.poster?.preview?{...n.state,poster:{...n.state.poster,preview:void 0}}:n.state;return r.append("editState",JSON.stringify(h)),r}var G=[{id:"bw",label:"\u9ED1\u767D",vf:"hue=s=0",css:"grayscale(1)"},{id:"sepia",label:"\u590D\u53E4",vf:"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131",css:"sepia(0.85)"},{id:"warm",label:"\u6696\u9633",vf:"colorbalance=rs=.15:gs=.04:bs=-.15",css:"sepia(0.25) saturate(1.25) brightness(1.03)"},{id:"cool",label:"\u51B7\u8C03",vf:"colorbalance=rs=-.14:bs=.16",css:"hue-rotate(12deg) saturate(0.95) brightness(1.02)"},{id:"vivid",label:"\u9C9C\u8273",vf:"eq=saturation=1.45:contrast=1.08",css:"saturate(1.45) contrast(1.08)"}];function H(e){return e?G.find(t=>t.id===e):void 0}function W(e,t){const a=H(t)?.css??"";return[`brightness(${1+e.brightness})`,`contrast(${1+e.contrast})`,`saturate(${1+e.saturation})`,a].filter(Boolean).join(" ")}function K(e,t,a,n,r,i=1,o,c=!0){const h=R(n,r);e.width=Math.max(2,Math.round(h.w*i)),e.height=Math.max(2,Math.round(h.h*i));const s=e.getContext("2d");if(!s)return;const u=B(n.w,n.h,r.rotation),l=r.crop??{x:0,y:0,width:u.w,height:u.h},p=r.scale?.fit??"force",{src:w,dst:d}=L({width:l.width,height:l.height},h,p);p==="contain"&&(s.fillStyle="#000",s.fillRect(0,0,e.width,e.height)),s.filter=W(r.filters,r.filterPreset),s.save(),p==="contain"&&(s.beginPath(),s.rect(i*d.x,i*d.y,i*d.width,i*d.height),s.clip()),s.translate(i*d.x,i*d.y),s.scale(i*d.width/w.width,i*d.height/w.height),s.translate(-(l.x+w.x),-(l.y+w.y)),s.translate(u.w/2,u.h/2),s.rotate(r.rotation*I),s.scale(r.flipX?-1:1,r.flipY?-1:1);const m=L({width:a.w,height:a.h},{w:n.w,h:n.h},"cover");s.drawImage(t,m.src.x,m.src.y,m.src.width,m.src.height,-n.w/2,-n.h/2,n.w,n.h),s.restore(),s.filter="none",c&&r.overlays?.length&&(s.setTransform(i,0,0,i,0,0),x(s,r.overlays,o),s.setTransform(1,0,0,1,0,0))}function Q(e,t){return new Promise(a=>{const n=()=>{e.removeEventListener("seeked",n),a()};e.addEventListener("seeked",n),e.currentTime=Math.min(Math.max(0,t),e.duration||t)})}async function Z(e,t,a=160){const n=e.duration;if(!n||!isFinite(n)||t<=0)return[];const r=e.videoWidth||16,i=e.videoHeight||9,o=Math.min(a,r),c=Math.max(1,Math.round(o*i/r)),h=document.createElement("canvas");h.width=o,h.height=c;const s=h.getContext("2d");if(!s)return[];const u=[];for(let l=0;l<t;l++)await Q(e,n*(l+.5)/t),s.drawImage(e,0,0,o,c),u.push(h.toDataURL("image/jpeg",.6));return u}function ee(e,t={}){const a=t.mode??"overlay",n=document.createElement("button");n.type="button",n.className=["me-fullscreen-toggle",t.className].filter(Boolean).join(" "),n.dataset.meFullscreenToggle="true",n.dataset.mode=a,n.title="\u5168\u5C4F / \u9000\u51FA\u5168\u5C4F",n.style.cssText=[a==="overlay"?"position:absolute;left:8px;bottom:8px;z-index:30;":"position:static;","width:32px;height:32px;padding:0;","display:inline-flex;align-items:center;justify-content:center;","border:1px solid var(--me-border,#26262b);border-radius:6px;","background:var(--me-chip,#1c1c20);color:var(--me-fg,#e7e7ee);","cursor:pointer;font-size:15px;line-height:1;opacity:0.9;font:inherit;"].join(""),e.classList.add("me-fullscreen-host");const r=()=>{const c=document.fullscreenElement===e;n.textContent=c?"\xD7":"\u26F6",n.setAttribute("aria-label",c?"\u9000\u51FA\u5168\u5C4F":"\u5168\u5C4F"),e.classList.toggle("me-is-fullscreen",c),e.dataset.meFullscreen=c?"true":"false"};r();const i=()=>r(),o=()=>{(document.fullscreenElement===e?document.exitFullscreen?.():e.requestFullscreen?.())?.catch?.(()=>{})};return n.addEventListener("click",o),document.addEventListener("fullscreenchange",i),{button:n,dispose:()=>{document.removeEventListener("fullscreenchange",i),n.removeEventListener("click",o),n.remove(),e.classList.remove("me-fullscreen-host","me-is-fullscreen"),delete e.dataset.meFullscreen}}}exports.buildVideoExportFormData=q,exports.createFullscreenToggle=ee,exports.drawOverlay=T,exports.drawOverlays=x,exports.drawVideoFrame=K,exports.fitStickerBox=_,exports.generateThumbnails=Z,exports.getOverlayRotation=g,exports.hitTestOverlay=$,exports.loadOverlayImages=P,exports.overlayBBox=S,exports.renderOverlaysToPng=E,exports.rotateOverlay=U,exports.scaleOverlay=N,exports.translateOverlay=Y;
@@ -0,0 +1,100 @@
1
+ import { O as OverlayT, V as VideoEditStateT } from './state-B85vkf7_.js';
2
+ import { VideoEditorEngine } from './engine.js';
3
+ import 'zod';
4
+
5
+ /**
6
+ * editor-core/overlay-render —— 标注/贴纸绘制(浏览器环境,Canvas API;零框架依赖)。
7
+ * 交互画布与导出 PNG 共用 drawOverlays,保证所见即所得。
8
+ * 坐标系 = 最终输出空间(旋转/裁剪/缩放后),导出 PNG 即按输出分辨率渲染。
9
+ */
10
+
11
+ declare function getOverlayRotation(o: OverlayT): number;
12
+ declare function overlayBBox(o: OverlayT): {
13
+ x: number;
14
+ y: number;
15
+ w: number;
16
+ h: number;
17
+ };
18
+ /** 单个对象绘制;sticker 的位图经 imageCache 提供(加载由调用方负责) */
19
+ declare function drawOverlay(ctx: CanvasRenderingContext2D, o: OverlayT, imageCache?: Map<string, HTMLImageElement>): void;
20
+ declare function drawOverlays(ctx: CanvasRenderingContext2D, overlays: OverlayT[], imageCache?: Map<string, HTMLImageElement>): void;
21
+ /** sticker 位图预加载(dataURL → HTMLImageElement) */
22
+ declare function loadOverlayImages(overlays: OverlayT[]): Promise<Map<string, HTMLImageElement>>;
23
+ /** 导出:把 overlays 渲染成输出分辨率的透明 PNG Blob(无 overlay 返回 null) */
24
+ declare function renderOverlaysToPng(overlays: OverlayT[] | undefined, width: number, height: number): Promise<Blob | null>;
25
+ /** 命中检测(选中/拖动用):返回最上层命中的 overlay 下标,无命中 -1 */
26
+ declare function hitTestOverlay(overlays: OverlayT[], x: number, y: number, tolerance?: number): number;
27
+ /**
28
+ * 贴纸图片等比落盒:长边 = boxSide、短边按原始宽高比,下限 8px。
29
+ * 上传任意比例图片不再被压成正方形(drawImage 是拉伸语义,入库 w/h 必须等比)。
30
+ */
31
+ declare function fitStickerBox(natW: number, natH: number, boxSide: number): {
32
+ w: number;
33
+ h: number;
34
+ };
35
+ /**
36
+ * 缩放 overlay(选中后拖右下角把手):以对象左上角为锚,按 ratio 等比。
37
+ * sticker/rect/ellipse 改 w/h;text 改 fontSize;pen/line/arrow 不支持(原样返回)。
38
+ */
39
+ declare function scaleOverlay(o: OverlayT, ratio: number): OverlayT;
40
+ /** 旋转 overlay:以对象 bbox 中心为视觉锚点;坐标本身不变,绘制/命中检测按 rotation 处理。 */
41
+ declare function rotateOverlay(o: OverlayT, deg: number): OverlayT;
42
+ /** 平移 overlay(拖动选中对象) */
43
+ declare function translateOverlay(o: OverlayT, dx: number, dy: number): OverlayT;
44
+
45
+ /**
46
+ * 把引擎导出计划 + 浏览器端 File 组装成服务端约定的 FormData
47
+ * (video_0../audio_0../overlay/editState),供 @media-editor/client.exportVideo 直接发。
48
+ * 触碰 DOM(overlay → canvas PNG),故归 @media-editor/core/browser,React/Vue 共用。
49
+ */
50
+
51
+ /**
52
+ * @param videoFiles 以「原始 srcIdx」为下标的视频 File 数组(引擎按 videoSrcOrder 取并重排)
53
+ * @param audioFiles 同上(音频)
54
+ */
55
+ declare function buildVideoExportFormData(engine: VideoEditorEngine, videoFiles: ReadonlyArray<File | undefined>, audioFiles?: ReadonlyArray<File | undefined>): Promise<FormData>;
56
+
57
+ /**
58
+ * 帧合成器(框架无关 canvas)—— 把「源帧 → 输出画布 + 完整效果链 + overlays」绘到 canvas。
59
+ * 从 SocialEcho VideoFramePreview.drawFinalFrame 抽出,供实时预览与封面导出复用。
60
+ *
61
+ * 效果链与 ffmpeg 导出严格同构:源→画布 cover 归一 → flips → rotate → crop → scale + 调色/滤镜 css。
62
+ */
63
+
64
+ /** drawImage 可接受的源(video / image / canvas) */
65
+ type FrameSource = CanvasImageSource;
66
+ /**
67
+ * 把一帧合成绘到 canvas(物理分辨率 = 输出尺寸 × k)。
68
+ * @param srcDims 活动源原始分辨率(逐片段可能不同)
69
+ * @param canvasDims 输出画布(= 首素材分辨率),全局效果链的「源 dims」
70
+ * @param k 物理像素倍率(预览用 ≤1 控带宽,封面导出用 1 全分辨率)
71
+ * @param imageCache 贴纸图片缓存(loadOverlayImages 产出)
72
+ */
73
+ declare function drawVideoFrame(canvas: HTMLCanvasElement, source: FrameSource, srcDims: {
74
+ w: number;
75
+ h: number;
76
+ }, canvasDims: {
77
+ w: number;
78
+ h: number;
79
+ }, state: VideoEditStateT, k?: number, imageCache?: Map<string, HTMLImageElement>, withOverlays?: boolean): void;
80
+ /**
81
+ * 抽 count 张等距缩略图(dataURL,jpeg)。供时间轴缩略图条 / 封面条。
82
+ * 传入**专用离屏 video 元素**(勿用主预览源,seek 会打断播放)。
83
+ */
84
+ declare function generateThumbnails(videoEl: HTMLVideoElement, count: number, maxW?: number): Promise<string[]>;
85
+
86
+ /**
87
+ * 全屏切换按钮(框架无关 DOM)。点按对 host 进/出全屏;监听 fullscreenchange 切图标和 host 状态类。
88
+ * 图片/视频 mount 共用:默认可作为覆盖按钮,也可放进宿主自己的返回工具栏。
89
+ */
90
+ interface FullscreenToggle {
91
+ button: HTMLButtonElement;
92
+ dispose: () => void;
93
+ }
94
+ interface FullscreenToggleOptions {
95
+ mode?: 'overlay' | 'inline';
96
+ className?: string;
97
+ }
98
+ declare function createFullscreenToggle(host: HTMLElement, options?: FullscreenToggleOptions): FullscreenToggle;
99
+
100
+ export { type FrameSource, type FullscreenToggle, type FullscreenToggleOptions, buildVideoExportFormData, createFullscreenToggle, drawOverlay, drawOverlays, drawVideoFrame, fitStickerBox, generateThumbnails, getOverlayRotation, hitTestOverlay, loadOverlayImages, overlayBBox, renderOverlaysToPng, rotateOverlay, scaleOverlay, translateOverlay };
@@ -0,0 +1,3 @@
1
+ import{outputSize as G,rotatedSize as Tt,fitRects as it,buildFilterCss as at,DEG2RAD as St,findFilterPreset as Ct}from"./chunk-USY6UDGL.js";var st=Math.PI/180;function D(t,e,r){t.strokeStyle=e,t.lineWidth=r,t.lineCap="round",t.lineJoin="round"}function Ft(t,e,r,n,i,a){const c=Math.atan2(i-r,n-e),o=Math.max(12,a*3.5);t.beginPath(),t.moveTo(n,i),t.lineTo(n-o*Math.cos(c-Math.PI/7),i-o*Math.sin(c-Math.PI/7)),t.moveTo(n,i),t.lineTo(n-o*Math.cos(c+Math.PI/7),i-o*Math.sin(c+Math.PI/7)),t.stroke()}function ot(t){if(!Number.isFinite(t))return 0;let e=t%360;return e>180&&(e-=360),e<-180&&(e+=360),Math.abs(e)<.001?0:e}var At=.84;function Nt(t){const e=Math.max(8,Number(t?.w)||0),r=Math.max(8,Number(t?.h)||0),n=Math.max(8,Math.min(e,r)*At);return{x:(Number(t?.x)||0)+(e-n)/2,y:(Number(t?.y)||0)+(r-n)/2,size:n}}var V=null;function Ot(){return typeof document>"u"?null:(V??(V=document.createElement("canvas")),V.getContext("2d"))}function ct(t){return Math.min(512,Math.max(8,Number(t.fontSize)||24))}function kt(t,e){return Number.isFinite(t.paddingX)?Math.max(0,t.paddingX):Math.max(8,Math.round(e*.18))}function Pt(t,e){return Number.isFinite(t.paddingY)?Math.max(0,t.paddingY):Math.max(6,Math.round(e*.14))}function Et(t,e){return(Number.isFinite(t.lineHeight)?Math.max(.9,t.lineHeight):1.1)*e}function Wt(t){return t.textAlign==="center"||t.textAlign==="right"?t.textAlign:"left"}function It(t){const e=ct(t),r=t.fontStyle||"normal",n=t.fontWeight||"700",i=t.fontFamily||'-apple-system, "PingFang SC", "Microsoft YaHei", sans-serif';return`${r} ${n} ${e}px ${i}`}function zt(t,e){const r=t==null?"":String(t);switch(e){case"uppercase":return r.toUpperCase();case"lowercase":return r.toLowerCase();case"capitalize":return r.toLowerCase().replace(/(^|\s)(\S)/g,(n,i,a)=>`${i}${a.toUpperCase()}`);default:return r}}function Bt(t,e){const n=zt(t,e).replace(/\r\n/g,`
2
+ `).split(`
3
+ `);return n.length?n:[""]}function X(t){return Number.isFinite(t)&&t>=0}function Lt(t){if(!J(t))return null;const e=X(t.startAt)?Number(t.startAt):null,r=X(t.endAt)?Number(t.endAt):null;if(e==null&&r==null)return null;const n=Math.max(0,e??0),i=Math.max(n,r??n);return{start:n,end:i}}function lt(t){const e=Lt(t);return!!e&&e.end>e.start}function J(t){return t?.type==="pen"||t?.type==="line"||t?.type==="arrow"||t?.type==="rect"||t?.type==="ellipse"||t?.type==="text"||t?.type==="sticker"}function Yt(t){if(!J(t)&&t?.type!=="filter"&&t?.type!=="adjust")return null;const e=X(t.startAt)?Number(t.startAt):null,r=X(t.endAt)?Number(t.endAt):null;if(e==null&&r==null)return null;const n=Math.max(0,e??0),i=Math.max(n,r??n);return{start:n,end:i}}function jt(t,e){const r=Yt(t);return r?Number.isFinite(e)?e>=r.start&&e<=r.end:!1:!0}function Xt(t,e){return t?.length?Number.isFinite(e)?t.filter(r=>jt(r,e)):t:[]}function ut(t){return t?.type==="text"||t?.type==="sticker"||t?.type==="filter"||t?.type==="adjust"}function ht(t){return Number.isFinite(t?.timelineTrack)?Math.max(0,Math.round(Number(t.timelineTrack))):0}function dt(t){return X(t?.startAt)?Number(t.startAt):0}function q(t){const e=ct(t),r=kt(t,e),n=Pt(t,e),i=Et(t,e),a=Bt(t.text,t.textTransform),c=Ot(),o=It(t);c&&(c.font=o);const f=a.map(x=>{const y=x===""?" ":x;return c?c.measureText(y).width:Math.max(1,y.length)*e*.6}),s=f.length?Math.max(...f):e*.6,w=Math.max(e,a.length*i),b=Math.max(Number.isFinite(t.width)?t.width:0,s+r*2),m=w+n*2;return{font:o,fontSize:e,paddingX:r,paddingY:n,lineHeight:i,lines:a,widths:f,boxWidth:b,boxHeight:m,align:Wt(t)}}function Rt(t,e,r){return e.align==="center"?t.x+e.boxWidth/2-r/2:e.align==="right"?t.x+e.boxWidth-e.paddingX-r:t.x+e.paddingX}function $t(t,e,r,n,i,a){if(!e.textDecoration||a<=0)return;const c=r.fontSize,o=String(e.textDecoration).includes("underline"),f=String(e.textDecoration).includes("line-through");if(!(!o&&!f)){if(t.save(),t.strokeStyle=e.color||"#fff",t.lineWidth=Math.max(1,c/18),o){const s=i+c+Math.max(1,c*.08);t.beginPath(),t.moveTo(n,s),t.lineTo(n+a,s),t.stroke()}if(f){const s=i+c*.56;t.beginPath(),t.moveTo(n,s),t.lineTo(n+a,s),t.stroke()}t.restore()}}function K(t){return ot(t.rotation??0)}function ft(t){switch(t.type){case"pen":{let e=1/0,r=1/0,n=-1/0,i=-1/0;for(let a=0;a<t.points.length;a+=2)e=Math.min(e,t.points[a]),n=Math.max(n,t.points[a]),r=Math.min(r,t.points[a+1]),i=Math.max(i,t.points[a+1]);return{x:e,y:r,w:n-e,h:i-r}}case"line":case"arrow":return{x:Math.min(t.x1,t.x2),y:Math.min(t.y1,t.y2),w:Math.abs(t.x2-t.x1),h:Math.abs(t.y2-t.y1)};case"rect":case"ellipse":case"sticker":return{x:t.x,y:t.y,w:t.w,h:t.h};case"text":{const e=q(t);return{x:t.x,y:t.y,w:e.boxWidth,h:e.boxHeight}}}}function Q(t){const e=ft(t);return{x:e.x+e.w/2,y:e.y+e.h/2}}function Ht(t,e,r,n,i){const a=i*st,c=Math.cos(a),o=Math.sin(a),f=t-r,s=e-n;return{x:r+f*c-s*o,y:n+f*o+s*c}}function mt(t,e,r,n,i){return{x:r+(t-r)*i,y:n+(e-n)*i}}function Z(t,e,r){const n=K(e);if(n){const i=Q(e);t.save(),t.translate(i.x,i.y),t.rotate(n*st),t.translate(-i.x,-i.y),pt(t,e,r),t.restore();return}pt(t,e,r)}function pt(t,e,r){switch(e.type){case"pen":{D(t,e.color,e.width),t.beginPath(),t.moveTo(e.points[0],e.points[1]);for(let n=2;n<e.points.length;n+=2)t.lineTo(e.points[n],e.points[n+1]);t.stroke();break}case"line":case"arrow":{D(t,e.color,e.width),t.beginPath(),t.moveTo(e.x1,e.y1),t.lineTo(e.x2,e.y2),t.stroke(),e.type==="arrow"&&Ft(t,e.x1,e.y1,e.x2,e.y2,e.width);break}case"rect":{D(t,e.color,e.width),t.strokeRect(e.x,e.y,e.w,e.h);break}case"ellipse":{D(t,e.color,e.width),t.beginPath(),t.ellipse(e.x+e.w/2,e.y+e.h/2,Math.abs(e.w/2),Math.abs(e.h/2),0,0,Math.PI*2),t.stroke();break}case"text":{const n=q(e),i=Number.isFinite(e.opacity)?Math.min(1,Math.max(0,e.opacity/100)):1,a=Number.isFinite(e.borderWidth)?Math.max(0,e.borderWidth):0,c=e.autoOutline!==!1;t.save(),t.globalAlpha*=i,e.backgroundColor&&e.backgroundColor!=="transparent"&&(t.fillStyle=e.backgroundColor,t.fillRect(e.x,e.y,n.boxWidth,n.boxHeight)),t.fillStyle=e.color||"#fff",t.font=n.font,t.textBaseline="top",t.lineJoin="round";const o=e.boxShadow;o&&(t.shadowColor=o.color||"transparent",t.shadowOffsetX=o.x||0,t.shadowOffsetY=o.y||0,t.shadowBlur=o.blur||0),n.lines.forEach((f,s)=>{const w=n.widths[s]??0,b=Rt(e,n,w),m=e.y+n.paddingY+s*n.lineHeight;(a>0||c)&&(t.strokeStyle=a>0?e.borderColor||"#000":e.strokeColor||"rgba(0,0,0,0.45)",t.lineWidth=a>0?a:Math.max(1,n.fontSize/18),t.strokeText(f,b,m)),t.fillText(f,b,m),$t(t,e,n,b,m,w)}),t.restore();break}case"sticker":{if(e.emoji){const n=Nt(e);t.save(),t.font=`${n.size}px -apple-system, "Apple Color Emoji", "Segoe UI Emoji", sans-serif`,t.textAlign="center",t.textBaseline="middle",t.fillText(e.emoji,n.x+n.size/2,n.y+n.size/2),t.restore()}else if(e.src){const n=r?.get(e.src);n&&t.drawImage(n,e.x,e.y,e.w,e.h)}break}}}function tt(t,e,r){for(const n of e)Z(t,n,r)}async function gt(t){const e=new Map,r=[...new Set(t.filter(n=>n.type==="sticker"&&n.src).map(n=>n.src))];return await Promise.all(r.map(n=>new Promise(i=>{const a=new Image;a.onload=()=>{e.set(n,a),i()},a.onerror=()=>i(),a.src=n}))),e}async function et(t,e,r){if(!t?.length)return null;const n=document.createElement("canvas");n.width=e,n.height=r;const i=n.getContext("2d");if(!i)return null;const a=await gt(t);return tt(i,t,a),new Promise(c=>n.toBlob(o=>c(o),"image/png"))}function Dt(t,e,r,n=12){for(let i=t.length-1;i>=0;i--){const a=t[i];if(Ut(a,e,r,n))return i}return-1}function _t(t,e,r,n,i){return Math.abs(t-r)<=i&&Math.abs(e-n)<=i}function yt(t,e,r,n,i,a,c){const o=i-r,f=a-n,s=o*o+f*f||1,w=Math.max(0,Math.min(1,((t-r)*o+(e-n)*f)/s)),b=r+w*o,m=n+w*f;return(t-b)**2+(e-m)**2<=c*c}function Ut(t,e,r,n){const i=K(t);if(i){const a=Q(t),c=Ht(e,r,a.x,a.y,-i);return wt(t,c.x,c.y,n)}return wt(t,e,r,n)}function wt(t,e,r,n){switch(t.type){case"pen":{for(let i=0;i+3<t.points.length;i+=2)if(yt(e,r,t.points[i],t.points[i+1],t.points[i+2],t.points[i+3],n+t.width/2))return!0;return!1}case"line":case"arrow":return yt(e,r,t.x1,t.y1,t.x2,t.y2,n+t.width/2);case"rect":case"ellipse":return e>=t.x-n&&e<=t.x+t.w+n&&r>=t.y-n&&r<=t.y+t.h+n;case"text":{const i=q(t);return e>=t.x-n&&e<=t.x+i.boxWidth+n&&r>=t.y-n&&r<=t.y+i.boxHeight+n}case"sticker":return _t(e,r,t.x+t.w/2,t.y+t.h/2,Math.max(t.w,t.h)/2+n)}}function Gt(t,e,r){const n=Math.max(8,r);if(!(t>0)||!(e>0))return{w:n,h:n};const i=n/Math.max(t,e);return{w:Math.max(8,Math.round(t*i)),h:Math.max(8,Math.round(e*i))}}function Vt(t,e){const r=Math.max(.05,e),n=Q(t);switch(t.type){case"pen":return{...t,points:t.points.map((i,a)=>a%2===0?n.x+(i-n.x)*r:n.y+(i-n.y)*r)};case"line":case"arrow":{const i=mt(t.x1,t.y1,n.x,n.y,r),a=mt(t.x2,t.y2,n.x,n.y,r);return{...t,x1:i.x,y1:i.y,x2:a.x,y2:a.y}}case"rect":case"ellipse":case"sticker":return{...t,w:Math.max(8,t.w*r),h:Math.max(8,t.h*r)};case"text":return{...t,fontSize:Math.min(512,Math.max(8,t.fontSize*r)),width:Number.isFinite(t.width)?Math.max(80,t.width*r):t.width,paddingX:Number.isFinite(t.paddingX)?Math.max(0,t.paddingX*r):t.paddingX,paddingY:Number.isFinite(t.paddingY)?Math.max(0,t.paddingY*r):t.paddingY,borderWidth:Number.isFinite(t.borderWidth)?Math.max(0,t.borderWidth*r):t.borderWidth,boxShadow:t.boxShadow?{...t.boxShadow,x:(t.boxShadow.x||0)*r,y:(t.boxShadow.y||0)*r,blur:(t.boxShadow.blur||0)*r}:t.boxShadow};default:return t}}function Jt(t,e){return{...t,rotation:ot(e)}}function qt(t,e,r){switch(t.type){case"pen":{const n=t.points.map((i,a)=>a%2===0?i+e:i+r);return{...t,points:n}}case"line":case"arrow":return{...t,x1:t.x1+e,y1:t.y1+r,x2:t.x2+e,y2:t.y2+r};case"rect":case"ellipse":case"sticker":return{...t,x:t.x+e,y:t.y+r};case"text":return{...t,x:t.x+e,y:t.y+r}}}function Y(t,e){const r=Math.min(8192,Math.max(2,Math.round(Number(t)||e)));return r%2===0?r:r-1}function ce(t){const e=G(t.canvas,t),r=t?.exportSettings??null;if(!r)return e;const n=Number.isFinite(Number(r.width))&&Number(r.width)>0,i=Number.isFinite(Number(r.height))&&Number(r.height)>0;if(!n&&!i)return e;const a=e.w>0&&e.h>0?e.w/e.h:1;if(n&&i)return{w:Y(r.width,e.w),h:Y(r.height,e.h)};if(n){const o=Y(r.width,e.w);return{w:o,h:Y(o/a,e.h)}}const c=Y(r.height,e.h);return{w:Y(c*a,e.w),h:c}}function Kt(t){const e=String(t??"").match(/^data:(image\/(?:png|jpe?g));base64,([a-z0-9+/=]+)$/i);if(!e)return null;const r=atob(e[2]),n=new Uint8Array(r.length);for(let i=0;i<r.length;i++)n[i]=r.charCodeAt(i);return new Blob([n],{type:e[1].toLowerCase()})}async function Qt(t,e,r=[]){const n=t.getExportPlan(),i=new FormData;n.videoSrcOrder.forEach((m,x)=>{const y=e[m];y&&i.append(`video_${x}`,y,y.name||`video_${x}.mp4`)}),n.audioSrcOrder.forEach((m,x)=>{const y=r[m];y&&i.append(`audio_${x}`,y,y.name||`audio_${x}`)});const a=G(n.state.canvas,n.state),c=n.state.overlays??[],o=c.filter(m=>lt(m)),f=c.filter(m=>!lt(m)&&J(m)),s=await et(f,a.w,a.h);s&&i.append("overlay",s,"overlay.png");for(let m=0;m<o.length;m++){const x=await et([o[m]],a.w,a.h);x&&i.append(`textOverlay_${m}`,x,`text-overlay-${m}.png`)}const w=n.state.poster?.useAsVideoCover?Kt(n.state.poster.preview):null;w&&i.append("videoCover",w,"video-cover.png");const b=n.state.poster?.preview?{...n.state,poster:{...n.state.poster,preview:void 0}}:n.state;return i.append("editState",JSON.stringify(b)),i}function F(t){return Math.max(-1,Math.min(1,Number(t)||0))}function j(t){return Math.max(0,Math.min(1,Number(t)||0))}function T(t){return Math.max(0,Math.min(1,t))}function N(t){return Math.max(0,Math.min(255,t))}function W(t,e,r){if(t===e)return r<t?0:1;const n=Math.max(0,Math.min(1,(r-t)/(e-t)));return n*n*(3-2*n)}function nt(t){const e=W(.08,.4,t),r=1-W(.6,.92,t);return T(e*r*2.2)}function bt(t,e,r=0){const n=Math.sin(t*12.9898+e*78.233+r*37.719)*43758.5453;return n-Math.floor(n)}var I=null;function Zt(t,e){return typeof document>"u"?null:(I??(I=document.createElement("canvas")),I.width!==t&&(I.width=t),I.height!==e&&(I.height=e),I)}function xt(t,e,r,n){if(!n||n==="none")return;const i=Zt(e,r),a=i?.getContext("2d");!i||!a||(a.setTransform(1,0,0,1,0,0),a.clearRect(0,0,e,r),a.drawImage(t.canvas,0,0,e,r),t.save(),t.setTransform(1,0,0,1,0,0),t.clearRect(0,0,e,r),t.filter=n,t.drawImage(i,0,0,e,r),t.restore(),t.filter="none")}function te(t,e,r,n){const i=Ct(n?.filterPreset)?.css??"";xt(t,e,r,i)}function ee(t,e,r,n){xt(t,e,r,at(n??{},"")),Mt(t,e,r,n??{})}function ne(t={}){return["temperature","tint","vibrance","gamma","highlights","shadows","whites","blacks","lightSense"].some(r=>Math.abs(F(t[r]))>1e-4)?!0:["sharpen","clarity","grain","fade","vignette"].some(r=>j(t[r])>1e-4)}function Mt(t,e,r,n={}){if(!ne(n))return;let i;try{i=t.getImageData(0,0,e,r)}catch{return}const a=F(n.temperature),c=F(n.tint),o=F(n.vibrance),f=F(n.gamma),s=F(n.highlights),w=F(n.shadows),b=F(n.whites),m=F(n.blacks),x=F(n.lightSense),y=j(n.sharpen),O=j(n.clarity),z=j(n.grain),k=j(n.fade),R=j(n.vignette),_=1+f*(f>0?1:.5),M=f===0?1:1/Math.max(.01,_),P=a*.18,$=a*.02,H=-a*.18,rt=c*.1,vt=-c*.12,g=i.data;for(let u=0;u<g.length;u+=4){let d=g[u]/255,p=g[u+1]/255,h=g[u+2]/255;if((a!==0||c!==0)&&(d=T(d+P+rt),p=T(p+$+vt),h=T(h+H+rt)),o!==0){const l=Math.max(d,p,h),S=Math.min(d,p,h),C=l-S,v=(d+p+h)/3,A=o>0?o*(1-C):o*(.35+C*.65);d=T(v+(d-v)*(1+A)),p=T(v+(p-v)*(1+A)),h=T(v+(h-v)*(1+A))}if(f!==0&&(d=T(Math.pow(d,M)),p=T(Math.pow(p,M)),h=T(Math.pow(h,M))),s!==0||w!==0||b!==0||m!==0||x!==0||k!==0){const l=.2126*d+.7152*p+.0722*h,S=1-W(.18,.62,l),C=1-W(.04,.32,l),v=W(.38,.84,l),A=W(.7,.98,l),B=nt(l),E=w*S*.28+s*v*.24+m*C*.2+b*A*.2+x*B*.18+k*(.12+S*.06);if(d=T(d+E),p=T(p+E),h=T(h+E),k>0){const U=(d+p+h)/3,L=k*.16;d=T(d*(1-L)+U*L),p=T(p*(1-L)+U*L),h=T(h*(1-L)+U*L)}}g[u]=Math.round(d*255),g[u+1]=Math.round(p*255),g[u+2]=Math.round(h*255)}if(y>1e-4||O>1e-4){const u=new Uint8ClampedArray(g),d=e*4;for(let p=1;p<r-1;p++)for(let h=1;h<e-1;h++){const l=p*d+h*4,S=(u[l-4]+u[l+4]+u[l-d]+u[l+d]+u[l]*4)/8,C=(u[l-3]+u[l+5]+u[l-d+1]+u[l+d+1]+u[l+1]*4)/8,v=(u[l-2]+u[l+6]+u[l-d+2]+u[l+d+2]+u[l+2]*4)/8,A=(.2126*u[l]+.7152*u[l+1]+.0722*u[l+2])/255,B=Math.min(1.8,y*1.45+O*.9*nt(A));g[l]=N(u[l]+(u[l]-S)*B),g[l+1]=N(u[l+1]+(u[l+1]-C)*B),g[l+2]=N(u[l+2]+(u[l+2]-v)*B)}}if(z>1e-4){const u=z*26;for(let d=0;d<r;d++)for(let p=0;p<e;p++){const h=(d*e+p)*4,l=(.2126*g[h]+.7152*g[h+1]+.0722*g[h+2])/255,S=.4+nt(l)*.9,C=(bt(p,d)-.5)*u*S,v=(bt(p,d,1)-.5)*u*.22*z;g[h]=N(g[h]+C+v),g[h+1]=N(g[h+1]+C*.88),g[h+2]=N(g[h+2]+C-v)}}if(R>1e-4){const u=(e-1)/2,d=(r-1)/2,p=Math.sqrt(u*u+d*d)||1;for(let h=0;h<r;h++)for(let l=0;l<e;l++){const S=(h*e+l)*4,C=l-u,v=h-d,A=Math.sqrt(C*C+v*v)/p,E=1-W(.32,1,A)*R*.62;g[S]=N(g[S]*E),g[S+1]=N(g[S+1]*E),g[S+2]=N(g[S+2]*E)}}t.putImageData(i,0,0)}function re(t,e,r,n,i,a=1,c,o=!0){const f=G(n,i);t.width=Math.max(2,Math.round(f.w*a)),t.height=Math.max(2,Math.round(f.h*a));const s=t.getContext("2d");if(!s)return;const w=Tt(n.w,n.h,i.rotation),b=i.crop??{x:0,y:0,width:w.w,height:w.h},m=i.scale?.fit??"force",{src:x,dst:y}=it({width:b.width,height:b.height},f,m);m==="contain"&&(s.fillStyle="#000",s.fillRect(0,0,t.width,t.height)),s.filter=at(i.filters,i.filterPreset),s.save(),m==="contain"&&(s.beginPath(),s.rect(a*y.x,a*y.y,a*y.width,a*y.height),s.clip()),s.translate(a*y.x,a*y.y),s.scale(a*y.width/x.width,a*y.height/x.height),s.translate(-(b.x+x.x),-(b.y+x.y)),s.translate(w.w/2,w.h/2),s.rotate(i.rotation*St),s.scale(i.flipX?-1:1,i.flipY?-1:1);const O=it({width:r.w,height:r.h},{w:n.w,h:n.h},"cover");if(s.drawImage(e,O.src.x,O.src.y,O.src.width,O.src.height,-n.w/2,-n.h/2,n.w,n.h),s.restore(),s.filter="none",Mt(s,t.width,t.height,i.filters),o&&i.overlays?.length){const z=Number.isFinite(i?.__mePreviewTimelineTime)?Number(i.__mePreviewTimelineTime):null,k=z==null?i.overlays:Xt(i.overlays,z),R=k.map((M,P)=>({overlay:M,index:P})).filter(M=>ut(M.overlay)).sort((M,P)=>{const $=ht(P.overlay)-ht(M.overlay);if($!==0)return $;const H=dt(M.overlay)-dt(P.overlay);return Math.abs(H)>1e-6?H:M.index-P.index}),_=k.filter(M=>!ut(M));s.setTransform(a,0,0,a,0,0),R.forEach(M=>{if(M.overlay?.type==="filter"){s.setTransform(1,0,0,1,0,0),te(s,t.width,t.height,M.overlay),s.setTransform(a,0,0,a,0,0);return}if(M.overlay?.type==="adjust"){s.setTransform(1,0,0,1,0,0),ee(s,t.width,t.height,M.overlay),s.setTransform(a,0,0,a,0,0);return}Z(s,M.overlay,c)}),tt(s,_,c),s.setTransform(1,0,0,1,0,0)}}function ie(t,e){return new Promise(r=>{const n=()=>{t.removeEventListener("seeked",n),r()};t.addEventListener("seeked",n),t.currentTime=Math.min(Math.max(0,e),t.duration||e)})}async function ae(t,e,r=160){const n=t.duration;if(!n||!isFinite(n)||e<=0)return[];const i=t.videoWidth||16,a=t.videoHeight||9,c=Math.min(r,i),o=Math.max(1,Math.round(c*a/i)),f=document.createElement("canvas");f.width=c,f.height=o;const s=f.getContext("2d");if(!s)return[];const w=[];for(let b=0;b<e;b++)await ie(t,n*(b+.5)/e),s.drawImage(t,0,0,c,o),w.push(f.toDataURL("image/jpeg",.6));return w}function se(t,e={}){const r=e.mode??"overlay",n=document.createElement("button");n.type="button",n.className=["me-fullscreen-toggle",e.className].filter(Boolean).join(" "),n.dataset.meFullscreenToggle="true",n.dataset.mode=r,n.title="\u5168\u5C4F / \u9000\u51FA\u5168\u5C4F",n.style.cssText=[r==="overlay"?"position:absolute;left:8px;bottom:8px;z-index:30;":"position:static;","width:32px;height:32px;padding:0;","display:inline-flex;align-items:center;justify-content:center;","border:1px solid var(--me-border,#26262b);border-radius:6px;","background:var(--me-chip,#1c1c20);color:var(--me-fg,#e7e7ee);","cursor:pointer;font-size:15px;line-height:1;opacity:0.9;font:inherit;"].join(""),t.classList.add("me-fullscreen-host");const i=()=>{const o=document.fullscreenElement===t;n.textContent=o?"\xD7":"\u26F6",n.setAttribute("aria-label",o?"\u9000\u51FA\u5168\u5C4F":"\u5168\u5C4F"),t.classList.toggle("me-is-fullscreen",o),t.dataset.meFullscreen=o?"true":"false"};i();const a=()=>i(),c=()=>{(document.fullscreenElement===t?document.exitFullscreen?.():t.requestFullscreen?.())?.catch?.(()=>{})};return n.addEventListener("click",c),document.addEventListener("fullscreenchange",a),{button:n,dispose:()=>{document.removeEventListener("fullscreenchange",a),n.removeEventListener("click",c),n.remove(),t.classList.remove("me-fullscreen-host","me-is-fullscreen"),delete t.dataset.meFullscreen}}}export{Qt as buildVideoExportFormData,se as createFullscreenToggle,Z as drawOverlay,tt as drawOverlays,re as drawVideoFrame,Gt as fitStickerBox,ae as generateThumbnails,K as getOverlayRotation,Dt as hitTestOverlay,gt as loadOverlayImages,ft as overlayBBox,et as renderOverlaysToPng,Jt as rotateOverlay,Vt as scaleOverlay,qt as translateOverlay};
@@ -0,0 +1 @@
1
+ import{z as t}from"zod";var d={color:t.string().max(32),width:t.number().positive().max(200)},m={rotation:t.number().min(-180).max(180).optional()},l={startAt:t.number().min(0).optional(),endAt:t.number().min(0).optional(),timelineTrack:t.number().int().min(0).max(99).optional()},f=t.discriminatedUnion("type",[t.object({type:t.literal("pen"),points:t.array(t.number()).min(4),...d,...l,...m}),t.object({type:t.literal("line"),x1:t.number(),y1:t.number(),x2:t.number(),y2:t.number(),...d,...l,...m}),t.object({type:t.literal("arrow"),x1:t.number(),y1:t.number(),x2:t.number(),y2:t.number(),...d,...l,...m}),t.object({type:t.literal("rect"),x:t.number(),y:t.number(),w:t.number(),h:t.number(),...d,...l,...m}),t.object({type:t.literal("ellipse"),x:t.number(),y:t.number(),w:t.number(),h:t.number(),...d,...l,...m}),t.object({type:t.literal("text"),x:t.number(),y:t.number(),text:t.string().max(500),color:t.string().max(32),fontSize:t.number().positive().max(512),startAt:t.number().min(0).optional(),endAt:t.number().min(0).optional(),timelineTrack:t.number().int().min(0).max(99).optional(),...m}),t.object({type:t.literal("sticker"),x:t.number().optional(),y:t.number().optional(),w:t.number().positive().optional(),h:t.number().positive().optional(),emoji:t.string().max(16).optional(),src:t.string().optional(),startAt:t.number().min(0).optional(),endAt:t.number().min(0).optional(),timelineTrack:t.number().int().min(0).max(99).optional(),...m}),t.object({type:t.literal("filter"),x:t.number().optional(),y:t.number().optional(),w:t.number().positive().optional(),h:t.number().positive().optional(),filterPreset:t.string().max(32).optional(),...l,...m}),t.object({type:t.literal("adjust"),x:t.number(),y:t.number(),w:t.number().positive(),h:t.number().positive(),brightness:t.number().min(-1).max(1).default(0),contrast:t.number().min(-1).max(1).default(0),saturation:t.number().min(-1).max(1).default(0),temperature:t.number().min(-1).max(1).default(0),tint:t.number().min(-1).max(1).default(0),vibrance:t.number().min(-1).max(1).default(0),gamma:t.number().min(-1).max(1).default(0),highlights:t.number().min(-1).max(1).default(0),shadows:t.number().min(-1).max(1).default(0),whites:t.number().min(-1).max(1).default(0),blacks:t.number().min(-1).max(1).default(0),lightSense:t.number().min(-1).max(1).default(0),sharpen:t.number().min(0).max(1).default(0),clarity:t.number().min(0).max(1).default(0),grain:t.number().min(0).max(1).default(0),fade:t.number().min(0).max(1).default(0),vignette:t.number().min(0).max(1).default(0),...l,...m})]),x=t.object({srcIdx:t.number().int().min(0).max(7),in:t.number().min(0),out:t.number().min(0)}),h=t.object({srcIdx:t.number().int().min(0).max(2),track:t.number().int().min(0).default(0),startAt:t.number().min(0),in:t.number().min(0),out:t.number().min(0),speed:t.number().min(.5).max(2).default(1),volume:t.number().min(0).max(2),fadeIn:t.number().min(0).default(0),fadeOut:t.number().min(0).default(0)}),M=t.object({type:t.enum(["none","fade","slide","wipe","flip","clockWipe","star","circle","rectangle"]).default("none"),duration:t.number().min(0).max(2).default(.4)}),I=t.object({fileName:t.string().max(120).optional(),format:t.enum(["mp4","mov","mxf"]).default("mp4"),width:t.number().int().min(2).max(8192).optional(),height:t.number().int().min(2).max(8192).optional(),frameRate:t.number().int().min(12).max(120).default(30),videoBitrateKbps:t.number().int().min(100).max(5e4).optional(),audioBitrateKbps:t.number().int().min(32).max(1024).optional(),audioCodec:t.enum(["aac","mp3"]).default("aac")}).optional(),S=t.object({clips:t.array(x).min(1).max(50),audioClips:t.array(h).max(8).default([]),canvas:t.object({w:t.number().int().min(2).max(4096),h:t.number().int().min(2).max(4096)}),crop:t.object({x:t.number().min(0),y:t.number().min(0),width:t.number().positive(),height:t.number().positive()}).optional(),scale:t.object({width:t.number().positive(),height:t.number().positive(),fit:t.enum(["contain","cover","force"])}).optional(),rotation:t.number().min(-180).max(180).default(0),flipX:t.boolean().default(!1),flipY:t.boolean().default(!1),filters:t.object({brightness:t.number().min(-1).max(1).default(0),contrast:t.number().min(-1).max(1).default(0),saturation:t.number().min(-1).max(1).default(0),temperature:t.number().min(-1).max(1).default(0),tint:t.number().min(-1).max(1).default(0),vibrance:t.number().min(-1).max(1).default(0),gamma:t.number().min(-1).max(1).default(0),highlights:t.number().min(-1).max(1).default(0),shadows:t.number().min(-1).max(1).default(0),whites:t.number().min(-1).max(1).default(0),blacks:t.number().min(-1).max(1).default(0),lightSense:t.number().min(-1).max(1).default(0),sharpen:t.number().min(0).max(1).default(0),clarity:t.number().min(0).max(1).default(0),grain:t.number().min(0).max(1).default(0),fade:t.number().min(0).max(1).default(0),vignette:t.number().min(0).max(1).default(0)}).default({brightness:0,contrast:0,saturation:0,temperature:0,tint:0,vibrance:0,gamma:0,highlights:0,shadows:0,whites:0,blacks:0,lightSense:0,sharpen:0,clarity:0,grain:0,fade:0,vignette:0}),filterPreset:t.string().max(32).optional(),overlays:t.array(f).max(200).optional(),transitions:t.array(M).max(49).default([]),keepAudio:t.boolean().default(!0),poster:t.object({time:t.number().min(0),useAsVideoCover:t.boolean().optional(),preview:t.string().optional()}).optional(),exportSettings:I}).superRefine((e,i)=>{e.clips.forEach((n,a)=>{n.out<=n.in&&i.addIssue({code:t.ZodIssueCode.custom,message:`clips[${a}].out \u5FC5\u987B\u5927\u4E8E in`,path:["clips",a,"out"]})}),e.audioClips?.forEach((n,a)=>{n.out<=n.in&&i.addIssue({code:t.ZodIssueCode.custom,message:`audioClips[${a}].out \u5FC5\u987B\u5927\u4E8E in`,path:["audioClips",a,"out"]})}),(e.canvas.w%2!==0||e.canvas.h%2!==0)&&i.addIssue({code:t.ZodIssueCode.custom,message:"canvas \u5BBD\u9AD8\u5FC5\u987B\u4E3A\u5076\u6570",path:["canvas"]}),e.exportSettings?.width!=null&&e.exportSettings.width%2!==0&&i.addIssue({code:t.ZodIssueCode.custom,message:"exportSettings.width \u5FC5\u987B\u4E3A\u5076\u6570",path:["exportSettings","width"]}),e.exportSettings?.height!=null&&e.exportSettings.height%2!==0&&i.addIssue({code:t.ZodIssueCode.custom,message:"exportSettings.height \u5FC5\u987B\u4E3A\u5076\u6570",path:["exportSettings","height"]})});function j(){return{clips:[],audioClips:[],canvas:{w:2,h:2},rotation:0,flipX:!1,flipY:!1,filters:{brightness:0,contrast:0,saturation:0,temperature:0,tint:0,vibrance:0,gamma:0,highlights:0,shadows:0,whites:0,blacks:0,lightSense:0,sharpen:0,clarity:0,grain:0,fade:0,vignette:0},transitions:[],keepAudio:!0}}var o=.1;function c(e){return e.out-e.in}function g(e){return e.reduce((i,n)=>i+c(n),0)}function k(e,i){let n=0;for(let a=0;a<i&&a<e.length;a++)n+=c(e[a]);return n}function v(e,i){if(!e.length||i<0)return null;let n=0;for(let a=0;a<e.length;a++){const r=c(e[a]);if(i<n+r)return{idx:a,srcTime:e[a].in+(i-n)};n+=r}if(Math.abs(i-n)<1e-9||i<=n){const a=e.length-1;return{idx:a,srcTime:e[a].out}}return null}function E(e,i){const n=v(e,i);if(!n)return e;const a=e[n.idx];return n.srcTime<a.in+o||n.srcTime>a.out-o?e:[...e.slice(0,n.idx),{...a,out:n.srcTime},{...a,in:n.srcTime},...e.slice(n.idx+1)]}function T(e,i){return e.length<=1||!e[i]?e:e.filter((n,a)=>a!==i)}function N(e,i){const n=e[i];return n?[...e.slice(0,i+1),{...n},...e.slice(i+1)]:e}function B(e,i,n){if(i===n||!e[i]||n<0||n>=e.length)return e;const a=[...e],[r]=a.splice(i,1);return a.splice(n,0,r),a}function D(e,i,n,a,r){if(!e[i])return e;const u=e.map(s=>({...s}));return n==="in"?u[i].in=Math.min(Math.max(a,0),u[i].out-o):u[i].out=Math.max(Math.min(a,r),u[i].in+o),u}function F(e,i,n){const a=Math.max(Math.min(e.out,i),o),r=Math.min(Math.max(e.in,0),a-o),b=Math.min(Math.max(e.startAt,0),Math.max(0,n-o)),u=Math.max(o,a-r),s=Math.min(Math.max(Number(e.speed)||1,.5),2),A=Number.isInteger(e.track)&&e.track>=0?e.track:0,p=Math.min(Math.max(Number(e.fadeIn)||0,0),u),C=Math.min(Math.max(Number(e.fadeOut)||0,0),Math.max(0,u-p));return{...e,track:A,in:r,out:a,startAt:b,speed:s,fadeIn:p,fadeOut:C}}function O(e=[]){return(e??[]).reduce((i,n)=>{if(n?.type!=="text"&&n?.type!=="sticker")return i;const a=Number.isFinite(n?.startAt)?Math.max(0,Number(n.startAt)):0,r=Number.isFinite(n?.endAt)?Math.max(a,Number(n.endAt)):a;return Math.max(i,r)},0)}function P(e,i=[],n=[]){const a=g(e),r=i.reduce((u,s)=>Math.max(u,s.startAt+(s.out-s.in)),0),b=O(n);return Math.max(a,r,b)}function Z(e){return[...new Set(e.map(i=>i.srcIdx))].sort((i,n)=>i-n)}function R(e,i){const n=new Map(i.map((a,r)=>[a,r]));return e.map(a=>({...a,srcIdx:n.get(a.srcIdx)??0}))}var V=100;function H(e){return{past:[],present:e,future:[]}}function X(e,i){if(i===e.present)return e;const n=[...e.past,e.present];return n.length>V&&n.shift(),{past:n,present:i,future:[]}}function _(e,i){return i===e.present?e:{...e,present:i}}function y(e){return e.past.length>0}function w(e){return e.future.length>0}function z(e){return y(e)?{past:e.past.slice(0,-1),present:e.past[e.past.length-1],future:[e.present,...e.future]}:e}function K(e){if(!w(e))return e;const[i,...n]=e.future;return{past:[...e.past,e.present],present:i,future:n}}export{h as AudioClip,x as Clip,o as MIN_CLIP,f as Overlay,S as VideoEditState,w as canRedo,y as canUndo,F as clampAudioClip,c as clipDuration,k as clipStartsAt,P as contentDuration,H as createHistory,j as defaultVideoEditState,N as duplicateClip,v as locateOutput,X as pushHistory,K as redo,R as remapSrcIndices,T as removeClip,B as reorderClips,_ as replacePresent,E as splitAtOutput,g as totalDuration,D as trimClipEdge,z as undo,Z as usedVideoSrcIndices};
@@ -0,0 +1 @@
1
+ var s=Math.PI/180;function c(t,h,n){const r=o(n);if(r===0||r===180)return{w:t,h};if(r===90||r===270)return{w:h,h:t};const a=r*s;return{w:Math.round(Math.abs(t*Math.cos(a))+Math.abs(h*Math.sin(a))),h:Math.round(Math.abs(t*Math.sin(a))+Math.abs(h*Math.cos(a)))}}function o(t){return(t%360+360)%360}function i(t){const h=Math.round(t);return h-h%2}function w(t,h,n=40){const r=Math.min(Math.max(n,t.width),h.w),a=Math.min(Math.max(n,t.height),h.h),l=Math.min(Math.max(0,t.x),h.w-r),M=Math.min(Math.max(0,t.y),h.h-a);return{x:Math.round(l),y:Math.round(M),width:Math.round(r),height:Math.round(a)}}function e(t,h){let n=t.w,r=n/h;return r>t.h&&(r=t.h,n=r*h),{x:Math.round((t.w-n)/2),y:Math.round((t.h-r)/2),width:Math.round(n),height:Math.round(r)}}function f(t,h,n){const r={x:0,y:0,width:t.width,height:t.height},a={x:0,y:0,width:h.w,height:h.h};return n==="cover"?{src:e({w:t.width,h:t.height},h.w/h.h),dst:a}:n==="contain"?{src:r,dst:e({w:h.w,h:h.h},t.width/t.height)}:{src:r,dst:a}}function g(t,h){if(h.scale)return{w:i(h.scale.width),h:i(h.scale.height)};if(h.crop)return{w:i(h.crop.width),h:i(h.crop.height)};const n=c(t.w,t.h,h.rotation);return{w:i(n.w),h:i(n.h)}}var u=[{id:"bw",label:"\u9ED1\u767D",vf:"hue=s=0",css:"grayscale(1)"},{id:"sepia",label:"\u590D\u53E4",vf:"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131",css:"sepia(0.85)"},{id:"warm",label:"\u6696\u9633",vf:"colorbalance=rs=.15:gs=.04:bs=-.15",css:"sepia(0.25) saturate(1.25) brightness(1.03)"},{id:"cool",label:"\u51B7\u8C03",vf:"colorbalance=rs=-.14:bs=.16",css:"hue-rotate(12deg) saturate(0.95) brightness(1.02)"},{id:"vivid",label:"\u9C9C\u8273",vf:"eq=saturation=1.45:contrast=1.08",css:"saturate(1.45) contrast(1.08)"}];function d(t){return t?u.find(h=>h.id===t):void 0}function v(t,h){const n=d(h)?.css??"";return[`brightness(${1+t.brightness})`,`contrast(${1+t.contrast})`,`saturate(${1+t.saturation})`,n].filter(Boolean).join(" ")}export{s as DEG2RAD,u as FILTER_PRESETS,v as buildFilterCss,e as centeredMaxRect,w as clampRect,i as evenize,d as findFilterPreset,f as fitRects,o as normalizeDeg,g as outputSize,c as rotatedSize};