video-maker-mcp 0.1.3 → 0.1.5

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Local MCP storyboard video renderer for Codex-driven short video generation.
4
4
 
5
- `video-maker-mcp` does not run its own LLM and does not generate images itself. Codex writes the script and storyboard, uses its host image generation capability to create scene images, then this MCP server validates assets, generates Doubao/Volcengine narration, and renders a 9:16 MP4 with ffmpeg.
5
+ `video-maker-mcp` does not run its own LLM and does not generate images itself. Codex writes the script and storyboard, uses its host image generation capability to create scene images, then this MCP server validates assets, generates Doubao/Volcengine narration, and renders a 9:16 MP4 with ffmpeg. The requested duration is treated as a target; final video length follows the generated narration audio so speech is not cut off or padded with silence.
6
6
 
7
7
  ## Install With Codex
8
8
 
@@ -117,26 +117,73 @@ Once installed, ask Codex:
117
117
  The MCP workflow is:
118
118
 
119
119
  1. `check_environment`
120
- 2. `create_video_project`
121
- 3. `get_video_plan_schema`
122
- 4. `save_video_plan`
123
- 5. `list_required_assets`
124
- 6. Codex generates real host-generated images into the exact returned paths
125
- 7. `verify_assets`
126
- 8. Optional: `create_asset_contact_sheet`
127
- 9. `generate_audio`
128
- 10. `render_video`
129
- 11. Optional: `export_video`
120
+ 2. `assert_image_generation_contract`
121
+ 3. `create_video_project`
122
+ 4. `get_video_plan_schema`
123
+ 5. `save_video_plan`
124
+ 6. `list_required_assets`
125
+ 7. Codex generates the dedicated cover image and real scene images into the exact returned paths
126
+ 8. Optional fallback: `save_generated_image`
127
+ 9. `verify_assets`
128
+ 10. Optional: `create_asset_contact_sheet`
129
+ 11. `generate_audio`
130
+ 12. `render_video`
131
+ 13. Optional: `export_video`
130
132
 
131
133
  Important asset contract:
132
134
 
133
- - `list_required_assets` returns the only image paths the renderer will use, for example `assets/scene_001.png`.
135
+ - Preferred: the host supports `generate_image_to_file(prompt, absolutePath)`: call a real image model and save the generated bitmap directly to the requested local file path.
136
+ - Fallback: if the host image tool exposes a real generated image as a temporary local file or base64/data URL, call `save_generated_image(projectId, assetPath, sourcePath|imageBase64)` to let MCP persist it to the required asset path.
137
+ - If the host can only show generated images in chat and cannot expose a local file path or bytes/base64, stop. Do not continue with fallback graphics.
138
+ - `list_required_assets` returns the image paths the tool will use, including `assets/cover.png` and scene paths such as `assets/scene_001.png`.
134
139
  - Codex must save the actual generated scene image to each returned `absolutePath`.
135
- - Do not substitute SVGs, chart screenshots, CSS drawings, preview strips, or manually created placeholder graphics.
140
+ - The cover must be a dedicated, content-rich 9:16 cover image generated for the video. It should not be a first-frame extraction.
141
+ - Do not substitute SVGs, chart screenshots, CSS drawings, HTML/canvas/sharp scripted graphics, preview strips, first-frame extractions, or manually created placeholder graphics.
136
142
  - `verify_assets` rejects missing files, unreadable files, wrong aspect ratios, tiny files, suspicious placeholder-sized images, and PNG files with same-name SVG sources such as `scene_001.svg`.
137
143
  - `create_asset_contact_sheet` creates `output/asset_contact_sheet.png` from the exact image files that `render_video` will use. Check this if the preview does not match the intended generated images.
138
144
  - If you intentionally use very small stylized images, override the size threshold with `VIDEO_MAKER_MIN_ASSET_BYTES`.
139
145
 
146
+ `save_generated_image` accepts exactly one source:
147
+
148
+ ```json
149
+ {
150
+ "projectId": "vid_...",
151
+ "assetPath": "assets/scene_001.png",
152
+ "sourcePath": "/tmp/host-generated-image.png"
153
+ }
154
+ ```
155
+
156
+ or:
157
+
158
+ ```json
159
+ {
160
+ "projectId": "vid_...",
161
+ "assetPath": "assets/scene_001.png",
162
+ "imageBase64": "data:image/png;base64,..."
163
+ }
164
+ ```
165
+
166
+ It only writes to asset paths returned by `list_required_assets`, rejects SVG input, normalizes the bitmap to the target format, and immediately runs asset validation.
167
+
168
+ ## Timing Model
169
+
170
+ The video is audio-driven:
171
+
172
+ - `durationSec` in `video_plan.json` is used as a relative weight for each scene.
173
+ - After `generate_audio`, `render_video` reads the real narration duration with `ffprobe`.
174
+ - Scene durations and subtitle timing are scaled to fill the audio duration.
175
+ - The final MP4 duration is set to the audio duration, so narration is not cut off and the video does not continue after speech ends.
176
+
177
+ ## Subtitle Alignment
178
+
179
+ Subtitles are generated from provider timestamps, not from rough scene durations:
180
+
181
+ - `generate_audio` asks Doubao/Volcengine TTS for subtitle timestamps.
182
+ - Timestamped words are saved to `audio/alignment.json`.
183
+ - `render_video` refuses to render if the project has audio but no alignment file.
184
+ - `output/subtitles.srt` is built from the returned word timings, grouped into readable caption cues.
185
+ - If the selected TTS model or voice does not return timestamps, `generate_audio` fails instead of falling back to estimated subtitles.
186
+
140
187
  ## Output
141
188
 
142
189
  Projects are stored under:
@@ -149,6 +196,7 @@ Final files:
149
196
 
150
197
  - `output/final.mp4`
151
198
  - `output/subtitles.srt`
199
+ - `assets/cover.png`
152
200
  - `manifest.json`
153
201
  - `video_plan.json`
154
202
 
@@ -158,6 +206,12 @@ For user-facing delivery, ask Codex to pass `outputDir` to `render_video` or cal
158
206
  ~/Downloads/video-maker/<projectId>
159
207
  ```
160
208
 
209
+ When available, `export_video` also copies the dedicated cover to:
210
+
211
+ ```text
212
+ cover.png
213
+ ```
214
+
161
215
  ## Local Development
162
216
 
163
217
  ```bash
@@ -1,4 +1,5 @@
1
1
  export interface RequiredAsset {
2
+ kind: "scene" | "cover";
2
3
  sceneId: string;
3
4
  assetPath: string;
4
5
  absolutePath: string;
@@ -13,6 +14,7 @@ export interface RequiredAsset {
13
14
  };
14
15
  }
15
16
  export interface AssetIssue {
17
+ kind: "scene" | "cover";
16
18
  sceneId: string;
17
19
  assetPath: string;
18
20
  absolutePath: string;
@@ -20,6 +22,7 @@ export interface AssetIssue {
20
22
  error: string;
21
23
  }
22
24
  export interface VerifiedAsset {
25
+ kind: "scene" | "cover";
23
26
  sceneId: string;
24
27
  assetPath: string;
25
28
  absolutePath: string;
@@ -34,9 +37,38 @@ export interface AssetContactSheetResult {
34
37
  contactSheetPath: string;
35
38
  absolutePath: string;
36
39
  }
40
+ export interface SavedGeneratedImageResult {
41
+ projectId: string;
42
+ assetPath: string;
43
+ absolutePath: string;
44
+ source: "sourcePath" | "imageBase64";
45
+ asset: VerifiedAsset;
46
+ }
47
+ export interface ImageGenerationContract {
48
+ ok: false;
49
+ requiredCapability: "generate_image_to_file";
50
+ contract: {
51
+ operation: string;
52
+ mustUseRealImageModel: true;
53
+ mustSaveToExactAbsolutePath: true;
54
+ mustStopIfUnsupported: true;
55
+ forbiddenFallbacks: string[];
56
+ };
57
+ instruction: string;
58
+ }
59
+ export interface SaveGeneratedImageInput {
60
+ sourcePath?: string;
61
+ imageBase64?: string;
62
+ }
63
+ export declare function imageGenerationContract(): ImageGenerationContract;
37
64
  export declare function listRequiredAssets(projectId: string): Promise<RequiredAsset[]>;
38
65
  export declare function verifyAssets(projectId: string): Promise<{
39
66
  ok: boolean;
40
67
  assets: Array<VerifiedAsset | AssetIssue>;
41
68
  }>;
69
+ export declare function verifySceneAssets(projectId: string): Promise<{
70
+ ok: boolean;
71
+ assets: Array<VerifiedAsset | AssetIssue>;
72
+ }>;
73
+ export declare function saveGeneratedImage(projectId: string, assetPath: string, input: SaveGeneratedImageInput): Promise<SavedGeneratedImageResult>;
42
74
  export declare function createAssetContactSheet(projectId: string): Promise<AssetContactSheetResult>;
@@ -1,7 +1,8 @@
1
1
  import fs from "node:fs/promises";
2
+ import path from "node:path";
2
3
  import sharp from "sharp";
3
4
  import { readVideoPlan, markStatus } from "./project.js";
4
- import { toProjectPath } from "./paths.js";
5
+ import { resolveUserPath, toProjectPath } from "./paths.js";
5
6
  const DEFAULT_MIN_ASSET_BYTES = 150 * 1024;
6
7
  const MIN_ASSET_WIDTH = 720;
7
8
  const MIN_ASSET_HEIGHT = 1280;
@@ -14,9 +15,33 @@ function minAssetBytes() {
14
15
  const parsed = Number(raw);
15
16
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_MIN_ASSET_BYTES;
16
17
  }
18
+ export function imageGenerationContract() {
19
+ return {
20
+ ok: false,
21
+ requiredCapability: "generate_image_to_file",
22
+ contract: {
23
+ operation: "generate_image_to_file(prompt, absolutePath), or fallback save_generated_image(projectId, assetPath, sourcePath|imageBase64)",
24
+ mustUseRealImageModel: true,
25
+ mustSaveToExactAbsolutePath: true,
26
+ mustStopIfUnsupported: true,
27
+ forbiddenFallbacks: [
28
+ "chat-only image preview without local file output",
29
+ "SVG generation",
30
+ "SVG-to-PNG conversion",
31
+ "HTML/CSS/canvas drawing",
32
+ "sharp/Jimp/canvas scripted graphics",
33
+ "chart or infographic screenshots",
34
+ "first-frame extraction",
35
+ "placeholder or manually composed fallback images"
36
+ ]
37
+ },
38
+ instruction: "Preferred: the host must provide a real image generation capability that can save the generated bitmap directly to the requested absolutePath. Fallback: if the host can access a real generated image file path or image bytes/base64, call save_generated_image to let MCP persist it to assetPath. If neither is possible, stop and tell the user that this host does not satisfy video-maker-mcp's image generation contract."
39
+ };
40
+ }
17
41
  export async function listRequiredAssets(projectId) {
18
42
  const plan = await readVideoPlan(projectId);
19
- return plan.scenes.map((scene) => ({
43
+ const sceneAssets = plan.scenes.map((scene) => ({
44
+ kind: "scene",
20
45
  sceneId: scene.id,
21
46
  assetPath: scene.assetPath,
22
47
  absolutePath: toProjectPath(projectId, scene.assetPath),
@@ -27,66 +52,165 @@ export async function listRequiredAssets(projectId) {
27
52
  minHeight: MIN_ASSET_HEIGHT,
28
53
  aspectRatio: "9:16",
29
54
  minBytes: minAssetBytes(),
30
- note: "Use a real host-generated image saved exactly to this path. Do not create placeholder SVGs, charts, CSS screenshots, preview strips, or manually drawn fallback graphics."
55
+ note: "Use generate_image_to_file(prompt, absolutePath): a real image model output saved exactly to this path. Do not create placeholder SVGs, charts, screenshots, HTML/CSS/canvas/sharp scripted graphics, preview strips, or manually drawn fallback graphics. If unsupported, stop."
31
56
  }
32
57
  }));
58
+ return [
59
+ {
60
+ kind: "cover",
61
+ sceneId: "cover",
62
+ assetPath: "assets/cover.png",
63
+ absolutePath: toProjectPath(projectId, "assets/cover.png"),
64
+ prompt: buildCoverPrompt(plan),
65
+ durationSec: 0,
66
+ requirements: {
67
+ minWidth: MIN_ASSET_WIDTH,
68
+ minHeight: MIN_ASSET_HEIGHT,
69
+ aspectRatio: "9:16",
70
+ minBytes: minAssetBytes(),
71
+ note: "Use generate_image_to_file(prompt, absolutePath) to create a dedicated, content-rich vertical cover image. It should not be a screenshot, SVG, chart-only graphic, HTML/CSS/canvas/sharp scripted graphic, or first-frame extraction. If unsupported, stop."
72
+ }
73
+ },
74
+ ...sceneAssets
75
+ ];
76
+ }
77
+ function buildCoverPrompt(plan) {
78
+ if (plan.coverPrompt)
79
+ return plan.coverPrompt;
80
+ const sceneSummary = plan.scenes.slice(0, 5).map((scene) => scene.visualPrompt).join(" | ");
81
+ return [
82
+ `Create a dedicated 9:16 vertical cover image for a short video titled "${plan.title}".`,
83
+ "Make it richer and more clickable than a normal video frame: strong central subject, layered background details, clear editorial composition, premium thumbnail/cover quality.",
84
+ "Avoid tiny unreadable text, generic charts, SVG style, screenshots, UI mockups, and placeholder graphics.",
85
+ `Match this video style: ${plan.style}.`,
86
+ `Visual themes from the storyboard: ${sceneSummary}`
87
+ ].join(" ");
33
88
  }
34
89
  export async function verifyAssets(projectId) {
35
- const required = await listRequiredAssets(projectId);
36
- const assets = await Promise.all(required.map(async (asset) => {
90
+ return verifyProjectAssets(projectId, { includeCover: true });
91
+ }
92
+ export async function verifySceneAssets(projectId) {
93
+ return verifyProjectAssets(projectId, { includeCover: false });
94
+ }
95
+ async function verifyProjectAssets(projectId, options) {
96
+ const required = (await listRequiredAssets(projectId)).filter((asset) => options.includeCover || asset.kind !== "cover");
97
+ const assets = await Promise.all(required.map(validateRequiredAsset));
98
+ const ok = assets.every((asset) => asset.ok);
99
+ if (ok) {
100
+ const cover = assets.find((asset) => asset.ok && asset.kind === "cover");
101
+ await markStatus(projectId, "assets_ready", cover ? { coverPath: cover.assetPath } : {});
102
+ }
103
+ return { ok, assets };
104
+ }
105
+ async function validateRequiredAsset(asset) {
106
+ try {
107
+ await fs.access(asset.absolutePath);
108
+ const forbiddenSourcePath = asset.absolutePath.replace(/\.[^.]+$/, ".svg");
37
109
  try {
38
- await fs.access(asset.absolutePath);
39
- const forbiddenSourcePath = asset.absolutePath.replace(/\.[^.]+$/, ".svg");
40
- try {
41
- await fs.access(forbiddenSourcePath);
42
- throw new Error(`Found sibling SVG source file ${forbiddenSourcePath}. This asset appears to be a generated SVG/chart converted to PNG, not a host image-generation result.`);
43
- }
44
- catch (error) {
45
- if (error.code !== "ENOENT")
46
- throw error;
47
- }
48
- const stat = await fs.stat(asset.absolutePath);
49
- const metadata = await sharp(asset.absolutePath).metadata();
50
- if (!metadata.width || !metadata.height) {
51
- throw new Error("Image dimensions could not be read");
52
- }
53
- if (metadata.width < MIN_ASSET_WIDTH || metadata.height < MIN_ASSET_HEIGHT) {
54
- throw new Error(`Image is too small: ${metadata.width}x${metadata.height}; expected at least ${MIN_ASSET_WIDTH}x${MIN_ASSET_HEIGHT}`);
55
- }
56
- const aspectRatio = metadata.width / metadata.height;
57
- if (Math.abs(aspectRatio - TARGET_ASPECT_RATIO) > ASPECT_RATIO_TOLERANCE) {
58
- throw new Error(`Image aspect ratio is ${metadata.width}:${metadata.height}; expected 9:16 vertical imagery`);
59
- }
60
- const minimumBytes = minAssetBytes();
61
- if (stat.size < minimumBytes) {
62
- throw new Error(`Image file is suspiciously small: ${stat.size} bytes; expected at least ${minimumBytes} bytes. This often means a placeholder graphic was saved instead of a host-generated image.`);
63
- }
64
- return {
65
- sceneId: asset.sceneId,
66
- assetPath: asset.assetPath,
67
- absolutePath: asset.absolutePath,
68
- ok: true,
69
- width: metadata.width,
70
- height: metadata.height,
71
- bytes: stat.size,
72
- format: metadata.format
73
- };
110
+ await fs.access(forbiddenSourcePath);
111
+ throw new Error(`Found sibling SVG source file ${forbiddenSourcePath}. This asset appears to be a generated SVG/chart converted to PNG, not a host image-generation result.`);
74
112
  }
75
113
  catch (error) {
76
- return {
77
- sceneId: asset.sceneId,
78
- assetPath: asset.assetPath,
79
- absolutePath: asset.absolutePath,
80
- ok: false,
81
- error: error instanceof Error ? error.message : String(error)
82
- };
114
+ if (error.code !== "ENOENT")
115
+ throw error;
83
116
  }
84
- }));
85
- const ok = assets.every((asset) => asset.ok);
86
- if (ok) {
87
- await markStatus(projectId, "assets_ready");
117
+ const stat = await fs.stat(asset.absolutePath);
118
+ const metadata = await sharp(asset.absolutePath).metadata();
119
+ if (!metadata.width || !metadata.height) {
120
+ throw new Error("Image dimensions could not be read");
121
+ }
122
+ if (metadata.width < MIN_ASSET_WIDTH || metadata.height < MIN_ASSET_HEIGHT) {
123
+ throw new Error(`Image is too small: ${metadata.width}x${metadata.height}; expected at least ${MIN_ASSET_WIDTH}x${MIN_ASSET_HEIGHT}`);
124
+ }
125
+ const aspectRatio = metadata.width / metadata.height;
126
+ if (Math.abs(aspectRatio - TARGET_ASPECT_RATIO) > ASPECT_RATIO_TOLERANCE) {
127
+ throw new Error(`Image aspect ratio is ${metadata.width}:${metadata.height}; expected 9:16 vertical imagery`);
128
+ }
129
+ const minimumBytes = minAssetBytes();
130
+ if (stat.size < minimumBytes) {
131
+ throw new Error(`Image file is suspiciously small: ${stat.size} bytes; expected at least ${minimumBytes} bytes. This often means a placeholder graphic was saved instead of a host-generated image.`);
132
+ }
133
+ return {
134
+ kind: asset.kind,
135
+ sceneId: asset.sceneId,
136
+ assetPath: asset.assetPath,
137
+ absolutePath: asset.absolutePath,
138
+ ok: true,
139
+ width: metadata.width,
140
+ height: metadata.height,
141
+ bytes: stat.size,
142
+ format: metadata.format
143
+ };
88
144
  }
89
- return { ok, assets };
145
+ catch (error) {
146
+ return {
147
+ kind: asset.kind,
148
+ sceneId: asset.sceneId,
149
+ assetPath: asset.assetPath,
150
+ absolutePath: asset.absolutePath,
151
+ ok: false,
152
+ error: error instanceof Error ? error.message : String(error)
153
+ };
154
+ }
155
+ }
156
+ export async function saveGeneratedImage(projectId, assetPath, input) {
157
+ const required = (await listRequiredAssets(projectId)).find((asset) => asset.assetPath === assetPath);
158
+ if (!required) {
159
+ throw new Error(`assetPath is not required by this project: ${assetPath}`);
160
+ }
161
+ if ((input.sourcePath ? 1 : 0) + (input.imageBase64 ? 1 : 0) !== 1) {
162
+ throw new Error("Provide exactly one of sourcePath or imageBase64.");
163
+ }
164
+ const source = input.sourcePath ? "sourcePath" : "imageBase64";
165
+ const bytes = input.sourcePath ? await readSourceImage(input.sourcePath) : decodeImageBase64(input.imageBase64 ?? "");
166
+ const metadata = await sharp(bytes).metadata();
167
+ if (metadata.format === "svg") {
168
+ throw new Error("SVG input is not accepted. Provide a real bitmap generated by an image model.");
169
+ }
170
+ await fs.mkdir(path.dirname(required.absolutePath), { recursive: true });
171
+ await sharp(bytes)
172
+ .rotate()
173
+ .toFormat(outputFormat(required.assetPath))
174
+ .toFile(required.absolutePath);
175
+ const asset = await validateRequiredAsset(required);
176
+ if (!asset.ok) {
177
+ throw new Error(asset.error);
178
+ }
179
+ return {
180
+ projectId,
181
+ assetPath,
182
+ absolutePath: required.absolutePath,
183
+ source,
184
+ asset
185
+ };
186
+ }
187
+ async function readSourceImage(sourcePath) {
188
+ const resolved = resolveUserPath(sourcePath);
189
+ if (/\.svg$/i.test(resolved)) {
190
+ throw new Error("SVG sourcePath is not accepted. Provide a real generated bitmap file.");
191
+ }
192
+ return fs.readFile(resolved);
193
+ }
194
+ function decodeImageBase64(value) {
195
+ const trimmed = value.trim();
196
+ if (trimmed.startsWith("data:")) {
197
+ const match = /^data:([^;,]+)(?:;[^,]*)?;base64,(.*)$/s.exec(trimmed);
198
+ if (!match)
199
+ throw new Error("Invalid data URL. Expected data:image/...;base64,...");
200
+ if (match[1].includes("svg")) {
201
+ throw new Error("SVG data URL is not accepted. Provide a real generated bitmap.");
202
+ }
203
+ return Buffer.from(match[2], "base64");
204
+ }
205
+ return Buffer.from(trimmed, "base64");
206
+ }
207
+ function outputFormat(assetPath) {
208
+ const ext = path.extname(assetPath).toLowerCase();
209
+ if (ext === ".jpg" || ext === ".jpeg")
210
+ return "jpeg";
211
+ if (ext === ".webp")
212
+ return "webp";
213
+ return "png";
90
214
  }
91
215
  export async function createAssetContactSheet(projectId) {
92
216
  const required = await listRequiredAssets(projectId);
@@ -1 +1 @@
1
- {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/core/assets.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/core/assets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface TimedWord {
2
+ word: string;
3
+ startTime: number;
4
+ endTime: number;
5
+ confidence?: number;
6
+ }
7
+ export interface CaptionCue {
8
+ startSec: number;
9
+ endSec: number;
10
+ text: string;
11
+ }
12
+ export declare function buildCaptionCues(words: TimedWord[]): CaptionCue[];
@@ -0,0 +1,31 @@
1
+ const MAX_CAPTION_CHARS = 16;
2
+ const MAX_CAPTION_DURATION_SEC = 3.2;
3
+ const ENDING_PUNCTUATION = /[。!?!?;;::]$/;
4
+ export function buildCaptionCues(words) {
5
+ const cues = [];
6
+ let current = [];
7
+ const flush = () => {
8
+ if (current.length === 0)
9
+ return;
10
+ cues.push({
11
+ startSec: current[0].startTime,
12
+ endSec: current[current.length - 1].endTime,
13
+ text: current.map((item) => item.word).join("")
14
+ });
15
+ current = [];
16
+ };
17
+ for (const word of words) {
18
+ if (!Number.isFinite(word.startTime) || !Number.isFinite(word.endTime) || word.endTime <= word.startTime) {
19
+ continue;
20
+ }
21
+ current.push(word);
22
+ const text = current.map((item) => item.word).join("");
23
+ const duration = current[current.length - 1].endTime - current[0].startTime;
24
+ if (ENDING_PUNCTUATION.test(word.word) || text.length >= MAX_CAPTION_CHARS || duration >= MAX_CAPTION_DURATION_SEC) {
25
+ flush();
26
+ }
27
+ }
28
+ flush();
29
+ return cues;
30
+ }
31
+ //# sourceMappingURL=captions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captions.js","sourceRoot":"","sources":["../../src/core/captions.ts"],"names":[],"mappings":"AAaA,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,wBAAwB,GAAG,GAAG,CAAC;AACrC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AAE1C,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,IAAI,GAAiB,EAAE,CAAC;IAC9B,IAAI,OAAO,GAAgB,EAAE,CAAC;IAE9B,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACjC,IAAI,CAAC,IAAI,CAAC;YACR,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;YAC9B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO;YAC3C,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;SAChD,CAAC,CAAC;QACH,OAAO,GAAG,EAAE,CAAC;IACf,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACzG,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,iBAAiB,IAAI,QAAQ,IAAI,wBAAwB,EAAE,CAAC;YACnH,KAAK,EAAE,CAAC;QACV,CAAC;IACH,CAAC;IAED,KAAK,EAAE,CAAC;IACR,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -3,6 +3,7 @@ export interface ExportVideoResult {
3
3
  exportDir: string;
4
4
  files: {
5
5
  video: string;
6
+ cover?: string;
6
7
  subtitles?: string;
7
8
  manifest: string;
8
9
  plan?: string;
@@ -11,6 +11,7 @@ export async function exportProjectVideo(projectId, outputDir) {
11
11
  await fs.mkdir(destinationDir, { recursive: true });
12
12
  const videoPath = path.join(destinationDir, "final.mp4");
13
13
  const manifestPath = path.join(destinationDir, "manifest.json");
14
+ const coverPath = path.join(destinationDir, "cover.png");
14
15
  const subtitlePath = manifest.subtitlePath ? path.join(destinationDir, "subtitles.srt") : undefined;
15
16
  const planPath = manifest.planPath ? path.join(destinationDir, "video_plan.json") : undefined;
16
17
  await markStatus(projectId, "rendered", {
@@ -18,6 +19,16 @@ export async function exportProjectVideo(projectId, outputDir) {
18
19
  exportedAt: new Date().toISOString()
19
20
  });
20
21
  await fs.copyFile(toProjectPath(projectId, manifest.outputPath), videoPath);
22
+ const projectCoverPath = manifest.coverPath ?? "assets/cover.png";
23
+ let exportedCoverPath;
24
+ try {
25
+ await fs.copyFile(toProjectPath(projectId, projectCoverPath), coverPath);
26
+ exportedCoverPath = coverPath;
27
+ }
28
+ catch (error) {
29
+ if (error.code !== "ENOENT")
30
+ throw error;
31
+ }
21
32
  await fs.copyFile(toProjectPath(projectId, "manifest.json"), manifestPath);
22
33
  if (manifest.subtitlePath && subtitlePath) {
23
34
  await fs.copyFile(toProjectPath(projectId, manifest.subtitlePath), subtitlePath);
@@ -30,6 +41,7 @@ export async function exportProjectVideo(projectId, outputDir) {
30
41
  exportDir: destinationDir,
31
42
  files: {
32
43
  video: videoPath,
44
+ cover: exportedCoverPath,
33
45
  subtitles: subtitlePath,
34
46
  manifest: manifestPath,
35
47
  plan: planPath
@@ -1 +1 @@
1
- {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/core/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAaxD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,SAAkB;IAC5E,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;IAC/C,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC;IAClG,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IAChE,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACpG,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE9F,MAAM,UAAU,CAAC,SAAS,EAAE,UAAU,EAAE;QACtC,YAAY,EAAE,SAAS;QACvB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC,CAAC;IAEH,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,CAAC;IAC5E,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,eAAe,CAAC,EAAE,YAAY,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,YAAY,IAAI,YAAY,EAAE,CAAC;QAC1C,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;IACnF,CAAC;IACD,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAClC,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO;QACL,SAAS;QACT,SAAS,EAAE,cAAc;QACzB,KAAK,EAAE;YACL,KAAK,EAAE,SAAS;YAChB,SAAS,EAAE,YAAY;YACvB,QAAQ,EAAE,YAAY;YACtB,IAAI,EAAE,QAAQ;SACf;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/core/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function getMediaDurationSec(filePath: string): Promise<number>;
@@ -0,0 +1,20 @@
1
+ import { execa } from "execa";
2
+ import { resolveBinary } from "./env.js";
3
+ export async function getMediaDurationSec(filePath) {
4
+ const ffprobe = await resolveBinary("ffprobe", ["-version"]);
5
+ if (!ffprobe.installed || !ffprobe.path) {
6
+ throw new Error("ffprobe is not available. Install ffmpeg to provide ffprobe.");
7
+ }
8
+ const result = await execa(ffprobe.path, [
9
+ "-v", "error",
10
+ "-show_entries", "format=duration",
11
+ "-of", "default=noprint_wrappers=1:nokey=1",
12
+ filePath
13
+ ]);
14
+ const duration = Number(result.stdout.trim());
15
+ if (!Number.isFinite(duration) || duration <= 0) {
16
+ throw new Error(`Could not read media duration for ${filePath}`);
17
+ }
18
+ return duration;
19
+ }
20
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/core/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAgB;IACxD,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,SAAS,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7D,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE;QACvC,IAAI,EAAE,OAAO;QACb,eAAe,EAAE,iBAAiB;QAClC,KAAK,EAAE,oCAAoC;QAC3C,QAAQ;KACT,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,qCAAqC,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -12,6 +12,7 @@ export declare const videoPlanSchema: z.ZodObject<{
12
12
  aspectRatio: z.ZodDefault<z.ZodLiteral<"9:16">>;
13
13
  language: z.ZodDefault<z.ZodLiteral<"zh-CN">>;
14
14
  style: z.ZodDefault<z.ZodString>;
15
+ coverPrompt: z.ZodOptional<z.ZodString>;
15
16
  scenes: z.ZodArray<z.ZodObject<{
16
17
  id: z.ZodString;
17
18
  durationSec: z.ZodNumber;
@@ -44,6 +45,12 @@ export declare const videoPlanJsonSchema: {
44
45
  readonly minLength: 1;
45
46
  readonly maxLength: 80;
46
47
  };
48
+ readonly coverPrompt: {
49
+ readonly type: "string";
50
+ readonly minLength: 8;
51
+ readonly maxLength: 1200;
52
+ readonly description: "Optional dedicated cover image prompt. The cover should be richer and more clickable than a video frame, but still match the video's subject and style.";
53
+ };
47
54
  readonly scenes: {
48
55
  readonly type: "array";
49
56
  readonly minItems: 1;
@@ -27,6 +27,7 @@ export const videoPlanSchema = z.object({
27
27
  aspectRatio: z.literal("9:16").default("9:16"),
28
28
  language: z.literal("zh-CN").default("zh-CN"),
29
29
  style: z.string().min(1).max(80).default("short_video_explainer"),
30
+ coverPrompt: z.string().min(8).max(1200).optional(),
30
31
  scenes: z.array(sceneSchema).min(1).max(20)
31
32
  }).superRefine((plan, ctx) => {
32
33
  const totalDuration = plan.scenes.reduce((sum, scene) => sum + scene.durationSec, 0);
@@ -59,6 +60,12 @@ export const videoPlanJsonSchema = {
59
60
  aspectRatio: { const: "9:16" },
60
61
  language: { const: "zh-CN" },
61
62
  style: { type: "string", minLength: 1, maxLength: 80 },
63
+ coverPrompt: {
64
+ type: "string",
65
+ minLength: 8,
66
+ maxLength: 1200,
67
+ description: "Optional dedicated cover image prompt. The cover should be richer and more clickable than a video frame, but still match the video's subject and style."
68
+ },
62
69
  scenes: {
63
70
  type: "array",
64
71
  minItems: 1,