@meframe/server 0.0.7 → 0.0.8
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.
- package/dist/cjs/ServerExporterBase.js +202 -41
- package/dist/cjs/ServerExporterBase.js.map +1 -1
- package/dist/cjs/postprocess/ffmpeg-audio-mix.js +100 -30
- package/dist/cjs/postprocess/ffmpeg-audio-mix.js.map +1 -1
- package/dist/cjs/utils/local-spool-server.js +173 -0
- package/dist/cjs/utils/local-spool-server.js.map +1 -0
- package/dist/cjs/utils/multipart-upload.js +5 -1
- package/dist/cjs/utils/multipart-upload.js.map +1 -1
- package/dist/esm/ServerExporterBase.d.ts.map +1 -1
- package/dist/esm/ServerExporterBase.js +203 -42
- package/dist/esm/ServerExporterBase.js.map +1 -1
- package/dist/esm/postprocess/ffmpeg-audio-mix.d.ts +35 -1
- package/dist/esm/postprocess/ffmpeg-audio-mix.d.ts.map +1 -1
- package/dist/esm/postprocess/ffmpeg-audio-mix.js +98 -30
- package/dist/esm/postprocess/ffmpeg-audio-mix.js.map +1 -1
- package/dist/esm/types.d.ts +26 -0
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils/local-spool-server.d.ts +17 -0
- package/dist/esm/utils/local-spool-server.d.ts.map +1 -0
- package/dist/esm/utils/local-spool-server.js +167 -0
- package/dist/esm/utils/local-spool-server.js.map +1 -0
- package/dist/esm/utils/multipart-upload.d.ts +1 -0
- package/dist/esm/utils/multipart-upload.d.ts.map +1 -1
- package/dist/esm/utils/multipart-upload.js +5 -1
- package/dist/esm/utils/multipart-upload.js.map +1 -1
- package/docs/INTEGRATION.md +58 -4
- package/package.json +2 -2
package/docs/INTEGRATION.md
CHANGED
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
适用读者:后端/平台工程同学(需要把导出能力集成进服务、队列、任务系统)。
|
|
9
9
|
|
|
10
|
+
### 重要更新:默认启用本地落盘(spool)模式
|
|
11
|
+
|
|
12
|
+
从当前版本开始,`@meframe/server` 默认使用 **spool-to-disk**(本地临时落盘)作为导出主路径:
|
|
13
|
+
|
|
14
|
+
- runner 在浏览器内仍然按 partSize 分片上传(`fetch(PUT)`),但目标不是对象存储,而是 **`@meframe/server` 启动的 localhost 临时 HTTP server**;
|
|
15
|
+
- Node 侧把分片拼成 `video-only.mp4`(本地文件),在 `audioSkipped` 常态下可直接作为 FFmpeg 输入;
|
|
16
|
+
- 最终仅由 Node 对 **最终文件**(`final.mp4` 或 fallback 的 `video-only.mp4`)执行一次 multipart upload 到你提供的 `store`。
|
|
17
|
+
|
|
18
|
+
你可以显式切回“runner 直传 store”模式(见下文 `runnerOutput` 章节)。
|
|
19
|
+
|
|
10
20
|
### 0. 你需要准备的 4 件东西(最重要)
|
|
11
21
|
|
|
12
22
|
要把导出跑起来,你最终只需要把这 4 个东西传给代码:
|
|
@@ -71,6 +81,31 @@ WebCodecs 等 API 需要 secure/trustworthy origin。`exportToStore({ pageUrl })
|
|
|
71
81
|
|
|
72
82
|
> 重要:这是运行时能力差异,不是业务代码“参数写错”。在不支持 AAC encode 的环境里,单纯升/降 Chrome 版本通常不可靠;生产上更稳的是启用 FFmpeg 兜底。
|
|
73
83
|
|
|
84
|
+
#### 2.6(新增)临时磁盘空间:spool 模式的硬盘风险与建议
|
|
85
|
+
|
|
86
|
+
spool 模式会在 Node 本机临时目录落盘中间产物:
|
|
87
|
+
|
|
88
|
+
- `video-only.mp4`:大小大约接近最终视频体积(无音频略小)
|
|
89
|
+
- `final.mp4`:如果启用 FFmpeg 混音,会额外产出一份最终文件(大小与最终体积接近)
|
|
90
|
+
|
|
91
|
+
因此磁盘峰值占用大致可按下面估算:
|
|
92
|
+
|
|
93
|
+
- **未启用 FFmpeg**:≈ `1 × 单任务视频体积 × 并发数`
|
|
94
|
+
- **启用 FFmpeg(常见)**:≈ `2 × 单任务视频体积 × 并发数`(再加少量分片临时文件开销)
|
|
95
|
+
|
|
96
|
+
这在以下环境中是风险点:
|
|
97
|
+
|
|
98
|
+
- 容器/平台提供的 ephemeral disk 较小(例如 `/tmp` 配额严格)
|
|
99
|
+
- 任务并发较高且单任务视频体积较大
|
|
100
|
+
|
|
101
|
+
建议:
|
|
102
|
+
|
|
103
|
+
- **把临时目录指到更大的 DATA 盘**(强烈建议生产配置):
|
|
104
|
+
- `runnerOutput.spool.tmpDirBase = '/data/meframe-tmp'`(示例)
|
|
105
|
+
- **限制并发峰值**:使用 `concurrency.maxJobs` 控制同时导出的任务数
|
|
106
|
+
- **保持默认清理**:`runnerOutput.spool.keepIntermediate` 默认 `false`,任务结束会自动清理临时目录;排障时才开启
|
|
107
|
+
- **必要时切回 store 模式**:如果运行环境禁止写磁盘/磁盘极小,可 `runnerOutput.target='store'`
|
|
108
|
+
|
|
74
109
|
#### 2.5 字体(可选,但字幕/文本强相关)
|
|
75
110
|
|
|
76
111
|
如果你的工程里存在字幕/文本(caption/text),并且使用了自定义字体(例如 `fontFamily: 'dtjinbu'`),那么你需要确保 Chromium 在导出时能加载到该字体:
|
|
@@ -358,6 +393,21 @@ export async function exportMedeoDraftToMp4(input: {
|
|
|
358
393
|
|
|
359
394
|
const exporter = new ServerExporter({
|
|
360
395
|
store,
|
|
396
|
+
// runner 分片输出目标:
|
|
397
|
+
// - 默认 target='spool':先写本地临时文件,再由 Node 统一上传最终文件(推荐,audioSkipped 常态下更省 IO)
|
|
398
|
+
// - 如需切回 runner 直传对象存储:runnerOutput: { target: 'store' }
|
|
399
|
+
runnerOutput: {
|
|
400
|
+
target: 'spool',
|
|
401
|
+
spool: {
|
|
402
|
+
// 强烈建议生产环境显式配置到更大的 DATA 盘,避免 /tmp 配额导致 ENOSPC
|
|
403
|
+
// tmpDirBase: '/data/meframe-tmp',
|
|
404
|
+
// keepIntermediate: false, // default
|
|
405
|
+
},
|
|
406
|
+
},
|
|
407
|
+
concurrency: {
|
|
408
|
+
// 建议结合磁盘配额设置合理并发,避免 spool 模式峰值占用过高
|
|
409
|
+
maxJobs: 1,
|
|
410
|
+
},
|
|
361
411
|
browser: {
|
|
362
412
|
executablePath: chromeExecutablePath,
|
|
363
413
|
headless: true,
|
|
@@ -393,11 +443,13 @@ export async function exportMedeoDraftToMp4(input: {
|
|
|
393
443
|
// 可选:ffmpeg/ffprobe 路径
|
|
394
444
|
// ffmpegPath: 'ffmpeg',
|
|
395
445
|
// ffprobePath: 'ffprobe',
|
|
396
|
-
//
|
|
397
|
-
// -
|
|
398
|
-
//
|
|
446
|
+
// 注意:
|
|
447
|
+
// - 当 runnerOutput.target='spool'(默认)时:FFmpeg 输入来自本地 `video-only.mp4`,
|
|
448
|
+
// 不需要实现 resolveUploadedInput(可以省略)。
|
|
449
|
+
// - 当 runnerOutput.target='store' 时:FFmpeg 需要读回已上传的 video-only MP4,
|
|
450
|
+
// 你必须实现 resolveUploadedInput(例如返回 S3 presigned GET URL)。
|
|
399
451
|
resolveUploadedInput: async ({ key }) => {
|
|
400
|
-
//
|
|
452
|
+
// 仅在 runnerOutput.target='store' 时需要:
|
|
401
453
|
// const url = await presignGetObjectUrl({ key, expiresInSeconds: 3600 });
|
|
402
454
|
// return { kind: 'url', url };
|
|
403
455
|
throw new Error(`resolveUploadedInput is not implemented for key: ${key}`);
|
|
@@ -432,6 +484,8 @@ export async function exportMedeoDraftToMp4(input: {
|
|
|
432
484
|
|
|
433
485
|
`ffmpegAudioMix.resolveUploadedInput()` 的目标是:**让 FFmpeg/FFprobe 能读取到已经上传完成的 video-only MP4**。
|
|
434
486
|
|
|
487
|
+
但请注意:只有当你选择 `runnerOutput.target='store'`(runner 直传对象存储)时,这个函数才是必需的;默认 `runnerOutput.target='spool'` 时 FFmpeg 输入来自本地文件,因此可以不实现。
|
|
488
|
+
|
|
435
489
|
推荐两种实现:
|
|
436
490
|
|
|
437
491
|
- **URL 方式(推荐)**:返回 `{ kind: 'url', url, headers? }`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meframe/server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Server-side exporter for @meframe/core (browser-driven, multipart upload via injected store)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"vite": "^5.4.20",
|
|
31
31
|
"typescript": "^5.3.3",
|
|
32
32
|
"vitest": "^1.3.1",
|
|
33
|
-
"@meframe/adapter-medeo": "0.0.
|
|
33
|
+
"@meframe/adapter-medeo": "0.0.8"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=18.0.0"
|