mulmocast 2.8.0 → 2.9.0

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.
@@ -103,6 +103,20 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
103
103
  kind: "path";
104
104
  path: string;
105
105
  } | undefined;
106
+ references?: {
107
+ name?: string | undefined;
108
+ source?: {
109
+ kind: "url";
110
+ url: string;
111
+ } | {
112
+ kind: "base64";
113
+ data: string;
114
+ } | {
115
+ kind: "path";
116
+ path: string;
117
+ } | undefined;
118
+ label?: string | undefined;
119
+ }[] | undefined;
106
120
  }> | undefined;
107
121
  backgroundImage?: string | {
108
122
  source: {
@@ -280,6 +294,7 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
280
294
  vertexai_location?: string | undefined;
281
295
  firstFrameImageName?: string | undefined;
282
296
  lastFrameImageName?: string | undefined;
297
+ frameFillColor?: string | undefined;
283
298
  referenceImages?: {
284
299
  imageName: string;
285
300
  referenceType: "ASSET" | "STYLE";
@@ -2315,6 +2330,7 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
2315
2330
  vertexai_location?: string | undefined;
2316
2331
  firstFrameImageName?: string | undefined;
2317
2332
  lastFrameImageName?: string | undefined;
2333
+ frameFillColor?: string | undefined;
2318
2334
  referenceImages?: {
2319
2335
  imageName: string;
2320
2336
  referenceType: "ASSET" | "STYLE";
@@ -2402,6 +2418,20 @@ export declare const createStudioData: (_mulmoScript: MulmoScript, fileName: str
2402
2418
  kind: "path";
2403
2419
  path: string;
2404
2420
  } | undefined;
2421
+ references?: {
2422
+ name?: string | undefined;
2423
+ source?: {
2424
+ kind: "url";
2425
+ url: string;
2426
+ } | {
2427
+ kind: "base64";
2428
+ data: string;
2429
+ } | {
2430
+ kind: "path";
2431
+ path: string;
2432
+ } | undefined;
2433
+ label?: string | undefined;
2434
+ }[] | undefined;
2405
2435
  }> | undefined;
2406
2436
  imageNames?: string[] | undefined;
2407
2437
  imagePrompt?: string | undefined;
@@ -2639,6 +2669,20 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
2639
2669
  kind: "path";
2640
2670
  path: string;
2641
2671
  } | undefined;
2672
+ references?: {
2673
+ name?: string | undefined;
2674
+ source?: {
2675
+ kind: "url";
2676
+ url: string;
2677
+ } | {
2678
+ kind: "base64";
2679
+ data: string;
2680
+ } | {
2681
+ kind: "path";
2682
+ path: string;
2683
+ } | undefined;
2684
+ label?: string | undefined;
2685
+ }[] | undefined;
2642
2686
  }> | undefined;
2643
2687
  backgroundImage?: string | {
2644
2688
  source: {
@@ -2816,6 +2860,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
2816
2860
  vertexai_location?: string | undefined;
2817
2861
  firstFrameImageName?: string | undefined;
2818
2862
  lastFrameImageName?: string | undefined;
2863
+ frameFillColor?: string | undefined;
2819
2864
  referenceImages?: {
2820
2865
  imageName: string;
2821
2866
  referenceType: "ASSET" | "STYLE";
@@ -4851,6 +4896,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4851
4896
  vertexai_location?: string | undefined;
4852
4897
  firstFrameImageName?: string | undefined;
4853
4898
  lastFrameImageName?: string | undefined;
4899
+ frameFillColor?: string | undefined;
4854
4900
  referenceImages?: {
4855
4901
  imageName: string;
4856
4902
  referenceType: "ASSET" | "STYLE";
@@ -4938,6 +4984,20 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
4938
4984
  kind: "path";
4939
4985
  path: string;
4940
4986
  } | undefined;
4987
+ references?: {
4988
+ name?: string | undefined;
4989
+ source?: {
4990
+ kind: "url";
4991
+ url: string;
4992
+ } | {
4993
+ kind: "base64";
4994
+ data: string;
4995
+ } | {
4996
+ kind: "path";
4997
+ path: string;
4998
+ } | undefined;
4999
+ label?: string | undefined;
5000
+ }[] | undefined;
4941
5001
  }> | undefined;
4942
5002
  imageNames?: string[] | undefined;
4943
5003
  imagePrompt?: string | undefined;
@@ -5182,6 +5242,20 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
5182
5242
  kind: "path";
5183
5243
  path: string;
5184
5244
  } | undefined;
5245
+ references?: {
5246
+ name?: string | undefined;
5247
+ source?: {
5248
+ kind: "url";
5249
+ url: string;
5250
+ } | {
5251
+ kind: "base64";
5252
+ data: string;
5253
+ } | {
5254
+ kind: "path";
5255
+ path: string;
5256
+ } | undefined;
5257
+ label?: string | undefined;
5258
+ }[] | undefined;
5185
5259
  }> | undefined;
5186
5260
  backgroundImage?: string | {
5187
5261
  source: {
@@ -5359,6 +5433,7 @@ export declare const initializeContextFromFiles: (files: FileObject, raiseError:
5359
5433
  vertexai_location?: string | undefined;
5360
5434
  firstFrameImageName?: string | undefined;
5361
5435
  lastFrameImageName?: string | undefined;
5436
+ frameFillColor?: string | undefined;
5362
5437
  referenceImages?: {
5363
5438
  imageName: string;
5364
5439
  referenceType: "ASSET" | "STYLE";
@@ -55,6 +55,7 @@ export declare const apiRateLimitErrorType = "apiRateLimit";
55
55
  export declare const apiKeyMissingType = "apiKeyMissing";
56
56
  export declare const invalidResponseType = "invalidResponse";
57
57
  export declare const voiceLimitReachedType = "voice_limit_reached";
58
+ export declare const invalidFrameSentinelType = "invalidFrameSentinel";
58
59
  export declare const movieAction = "movie";
59
60
  export declare const imageAction = "images";
60
61
  export declare const audioAction = "audio";
@@ -69,6 +70,10 @@ export declare const multiLingualFileTarget = "multiLingualFile";
69
70
  export declare const videoSourceTarget = "videoSource";
70
71
  export declare const audioSourceTarget = "audioSource";
71
72
  export declare const codeTextTarget = "codeText";
73
+ export declare const bothFramesTarget = "bothFrames";
74
+ export declare const missingBeatImageTarget = "missingBeatImage";
75
+ export declare const unsupportedImageTypeTarget = "unsupportedImageType";
76
+ export declare const missingFirstFrameTarget = "missingFirstFrame";
72
77
  export declare const agentFileNotExistError: (agentName: string, action: string, target: string, fileName: string, beatIndex?: number) => {
73
78
  beatIndex?: number | undefined;
74
79
  type: string;
@@ -115,6 +120,13 @@ export declare const invalidAudioSourceError: (beatIndex: number) => {
115
120
  agentName: string;
116
121
  beatIndex: number;
117
122
  };
123
+ export declare const beatImageSentinelError: (beatIndex: number, target: string) => {
124
+ type: string;
125
+ action: string;
126
+ target: string;
127
+ agentName: string;
128
+ beatIndex: number;
129
+ };
118
130
  export declare const downLoadReferenceImageError: (key: string, url: string) => {
119
131
  type: string;
120
132
  action: string;
@@ -56,6 +56,7 @@ export const apiRateLimitErrorType = "apiRateLimit";
56
56
  export const apiKeyMissingType = "apiKeyMissing";
57
57
  export const invalidResponseType = "invalidResponse";
58
58
  export const voiceLimitReachedType = "voice_limit_reached";
59
+ export const invalidFrameSentinelType = "invalidFrameSentinel";
59
60
  // Actions
60
61
  export const movieAction = "movie";
61
62
  export const imageAction = "images";
@@ -72,6 +73,10 @@ export const multiLingualFileTarget = "multiLingualFile";
72
73
  export const videoSourceTarget = "videoSource";
73
74
  export const audioSourceTarget = "audioSource";
74
75
  export const codeTextTarget = "codeText";
76
+ export const bothFramesTarget = "bothFrames";
77
+ export const missingBeatImageTarget = "missingBeatImage";
78
+ export const unsupportedImageTypeTarget = "unsupportedImageType";
79
+ export const missingFirstFrameTarget = "missingFirstFrame";
75
80
  // Agent File Not Exist Errors
76
81
  export const agentFileNotExistError = (agentName, action, target, fileName, beatIndex) => {
77
82
  return {
@@ -111,6 +116,16 @@ export const invalidAudioSourceError = (beatIndex) => {
111
116
  beatIndex,
112
117
  };
113
118
  };
119
+ // $beatImage frame sentinel misuse (invalid combination or beat cannot supply its own image)
120
+ export const beatImageSentinelError = (beatIndex, target) => {
121
+ return {
122
+ type: invalidFrameSentinelType,
123
+ action: imageAction,
124
+ target,
125
+ agentName: "imagePreprocessAgent",
126
+ beatIndex,
127
+ };
128
+ };
114
129
  // 404
115
130
  export const downLoadReferenceImageError = (key, url) => {
116
131
  return {
@@ -26,6 +26,11 @@ export declare const ffmpegGetMediaDuration: (filePath: string) => Promise<{
26
26
  duration: number;
27
27
  hasAudio: boolean;
28
28
  }>;
29
+ export declare const ffmpegGetImageDimensions: (filePath: string) => Promise<{
30
+ width: number;
31
+ height: number;
32
+ }>;
33
+ export declare const padImageToCanvas: (srcPath: string, destPath: string, width: number, height: number, fillColor: string) => Promise<void>;
29
34
  export declare const extractImageFromMovie: (movieFile: string, imagePath: string, useLastFrame?: boolean) => Promise<object>;
30
35
  export declare const trimMusic: (inputFile: string, startTime: number, duration: number) => Promise<Buffer>;
31
36
  export declare const createSilentAudio: (filePath: string, durationSec: number) => Promise<void>;
@@ -117,6 +117,48 @@ export const ffmpegGetMediaDuration = (filePath) => {
117
117
  });
118
118
  });
119
119
  };
120
+ export const ffmpegGetImageDimensions = (filePath) => {
121
+ return new Promise((resolve, reject) => {
122
+ ffmpeg.ffprobe(filePath, (err, metadata) => {
123
+ if (err) {
124
+ GraphAILogger.error("Error while getting image dimensions:", err);
125
+ reject(err);
126
+ return;
127
+ }
128
+ const stream = metadata.streams?.find((s) => s.codec_type === "video" && s.width && s.height);
129
+ if (!stream?.width || !stream?.height) {
130
+ reject(new Error(`ffmpegGetImageDimensions: no video stream found: ${filePath}`));
131
+ return;
132
+ }
133
+ resolve({ width: stream.width, height: stream.height });
134
+ });
135
+ });
136
+ };
137
+ // Aspect-fit the image into width x height, filling the extra space with fillColor (centered).
138
+ export const padImageToCanvas = (srcPath, destPath, width, height, fillColor) => {
139
+ // Only allow hex colors and color names: fillColor is interpolated into the
140
+ // filtergraph, where ',' and ':' would allow injecting arbitrary filters.
141
+ if (!/^(#|0x)?[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(fillColor) && !/^[a-zA-Z]+$/.test(fillColor)) {
142
+ return Promise.reject(new Error(`padImageToCanvas: invalid fill color: ${fillColor}`));
143
+ }
144
+ // ffmpeg color syntax: hex needs a 0x prefix ('#RRGGBB' and bare 'RRGGBB' both normalize)
145
+ const color = /^[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$/.test(fillColor) ? `0x${fillColor}` : fillColor.replace(/^#/, "0x");
146
+ return new Promise((resolve, reject) => {
147
+ ffmpeg(srcPath)
148
+ .outputOptions([
149
+ "-frames:v",
150
+ "1",
151
+ "-update",
152
+ "1",
153
+ "-vf",
154
+ `scale=w=${width}:h=${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:color=${color}`,
155
+ ])
156
+ .output(destPath)
157
+ .on("end", () => resolve())
158
+ .on("error", (err) => reject(err))
159
+ .run();
160
+ });
161
+ };
120
162
  export const extractImageFromMovie = (movieFile, imagePath, useLastFrame = false) => {
121
163
  return new Promise((resolve, reject) => {
122
164
  const command = ffmpeg(movieFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mulmocast",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.node.js",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "resolutions": {
27
27
  "minimatch": "^10.2.5",
28
- "tar": "7.5.19",
28
+ "tar": "7.5.20",
29
29
  "yauzl": "^3.4.0"
30
30
  },
31
31
  "bin": {
@@ -89,7 +89,7 @@
89
89
  "homepage": "https://github.com/receptron/mulmocast-cli#readme",
90
90
  "dependencies": {
91
91
  "@google-cloud/text-to-speech": "^6.4.1",
92
- "@google/genai": "^2.10.0",
92
+ "@google/genai": "^2.12.0",
93
93
  "@graphai/anthropic_agent": "^2.0.12",
94
94
  "@graphai/browserless_agent": "^2.0.3",
95
95
  "@graphai/gemini_agent": "^2.0.5",
@@ -102,7 +102,7 @@
102
102
  "@inquirer/input": "^5.1.2",
103
103
  "@inquirer/select": "^5.2.1",
104
104
  "@modelcontextprotocol/sdk": "^1.29.0",
105
- "@modernized/fluent-ffmpeg": "^1.0.1",
105
+ "@modernized/fluent-ffmpeg": "^1.0.2",
106
106
  "@mozilla/readability": "^0.6.0",
107
107
  "@mulmocast/deck": "^1.1.0",
108
108
  "@tavily/core": "^0.7.6",
@@ -112,8 +112,8 @@
112
112
  "graphai": "^2.0.18",
113
113
  "js-tiktoken": "^1.0.21",
114
114
  "jsdom": "^29.1.1",
115
- "marked": "^18.0.5",
116
- "mulmocast-vision": "^1.0.11",
115
+ "marked": "^18.0.6",
116
+ "mulmocast-vision": "^1.0.12",
117
117
  "ora": "^9.4.1",
118
118
  "puppeteer": "^25.3.0",
119
119
  "replicate": "^1.4.0",
@@ -132,12 +132,12 @@
132
132
  "eslint-config-prettier": "^10.1.8",
133
133
  "eslint-plugin-import": "^2.32.0",
134
134
  "eslint-plugin-prettier": "^5.5.6",
135
- "eslint-plugin-sonarjs": "^4.1.0",
135
+ "eslint-plugin-sonarjs": "^4.2.0",
136
136
  "globals": "^17.7.0",
137
137
  "prettier": "^3.9.5",
138
- "tsx": "^4.23.0",
138
+ "tsx": "^4.23.1",
139
139
  "typescript": "6.0.3",
140
- "typescript-eslint": "^8.63.0"
140
+ "typescript-eslint": "^8.64.0"
141
141
  },
142
142
  "engines": {
143
143
  "node": ">=22.0.0"