@mulmocast/slide 0.1.4 → 0.1.6

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 (39) hide show
  1. package/lib/actions/common.d.ts +1 -1
  2. package/lib/actions/common.d.ts.map +1 -1
  3. package/lib/actions/common.js +9 -0
  4. package/lib/actions/common.js.map +1 -1
  5. package/lib/actions/movie.js +2 -2
  6. package/lib/actions/movie.js.map +1 -1
  7. package/lib/actions/preview.d.ts +3 -0
  8. package/lib/actions/preview.d.ts.map +1 -0
  9. package/lib/actions/preview.js +147 -0
  10. package/lib/actions/preview.js.map +1 -0
  11. package/lib/cli.js +62 -5
  12. package/lib/cli.js.map +1 -1
  13. package/lib/convert/movie.d.ts +17 -0
  14. package/lib/convert/movie.d.ts.map +1 -0
  15. package/lib/convert/movie.js +397 -0
  16. package/lib/convert/movie.js.map +1 -0
  17. package/lib/convert/movie_bundle.d.ts +34 -0
  18. package/lib/convert/movie_bundle.d.ts.map +1 -0
  19. package/lib/convert/movie_bundle.js +217 -0
  20. package/lib/convert/movie_bundle.js.map +1 -0
  21. package/lib/utils/audio-save.d.ts +25 -0
  22. package/lib/utils/audio-save.d.ts.map +1 -0
  23. package/lib/utils/audio-save.js +190 -0
  24. package/lib/utils/audio-save.js.map +1 -0
  25. package/lib/utils/bundle-server.d.ts +10 -0
  26. package/lib/utils/bundle-server.d.ts.map +1 -0
  27. package/lib/utils/bundle-server.js +97 -0
  28. package/lib/utils/bundle-server.js.map +1 -0
  29. package/lib/utils/dependencies.d.ts.map +1 -1
  30. package/lib/utils/dependencies.js +7 -0
  31. package/lib/utils/dependencies.js.map +1 -1
  32. package/lib/vue/assets/index-D6am8L57.css +1 -0
  33. package/lib/vue/assets/index-xq-ZNfmX.js +2 -0
  34. package/lib/vue/index.html +13 -0
  35. package/lib/vue/main.d.ts +2 -0
  36. package/lib/vue/main.d.ts.map +1 -0
  37. package/lib/vue/main.js +10 -0
  38. package/lib/vue/main.js.map +1 -0
  39. package/package.json +16 -5
@@ -0,0 +1,397 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.convertMovie = convertMovie;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const child_process_1 = require("child_process");
43
+ const yargs_1 = __importDefault(require("yargs"));
44
+ const helpers_1 = require("yargs/helpers");
45
+ const lang_1 = require("../utils/lang");
46
+ const dependencies_1 = require("../utils/dependencies");
47
+ const openai_1 = __importDefault(require("openai"));
48
+ const mulmocast_1 = require("mulmocast");
49
+ const movie_bundle_1 = require("./movie_bundle");
50
+ // Get video duration using ffprobe
51
+ function getVideoDuration(videoPath) {
52
+ const result = (0, child_process_1.execSync)(`ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${videoPath}"`, { encoding: "utf-8" });
53
+ return parseFloat(result.trim());
54
+ }
55
+ // Detect silence intervals in video using FFmpeg
56
+ async function detectSilence(videoPath, noiseThreshold = -30, minSilenceDuration = 0.5) {
57
+ return new Promise((resolve, reject) => {
58
+ const silences = [];
59
+ let currentStart = null;
60
+ const ffmpeg = (0, child_process_1.spawn)("ffmpeg", [
61
+ "-i",
62
+ videoPath,
63
+ "-af",
64
+ `silencedetect=noise=${noiseThreshold}dB:d=${minSilenceDuration}`,
65
+ "-f",
66
+ "null",
67
+ "-",
68
+ ]);
69
+ let stderr = "";
70
+ ffmpeg.stderr.on("data", (data) => {
71
+ stderr += data.toString();
72
+ });
73
+ ffmpeg.on("close", (code) => {
74
+ if (code !== 0 && code !== null) {
75
+ // FFmpeg may return non-zero even on success for silence detection
76
+ }
77
+ // Parse silence_start and silence_end from stderr
78
+ const lines = stderr.split("\n");
79
+ for (const line of lines) {
80
+ const startMatch = line.match(/silence_start:\s*([\d.]+)/);
81
+ const endMatch = line.match(/silence_end:\s*([\d.]+)/);
82
+ if (startMatch) {
83
+ currentStart = parseFloat(startMatch[1]);
84
+ }
85
+ if (endMatch && currentStart !== null) {
86
+ silences.push({
87
+ start: currentStart,
88
+ end: parseFloat(endMatch[1]),
89
+ });
90
+ currentStart = null;
91
+ }
92
+ }
93
+ resolve(silences);
94
+ });
95
+ ffmpeg.on("error", reject);
96
+ });
97
+ }
98
+ // Calculate segment boundaries based on silence intervals
99
+ function calculateSegments(totalDuration, silences, minDuration = 20, maxDuration = 120) {
100
+ const segments = [];
101
+ let currentStart = 0;
102
+ let segmentIndex = 1;
103
+ // Get silence midpoints as potential split points
104
+ const splitPoints = silences.map((s) => (s.start + s.end) / 2);
105
+ while (currentStart < totalDuration) {
106
+ const targetEnd = currentStart + maxDuration;
107
+ if (targetEnd >= totalDuration) {
108
+ // Last segment
109
+ segments.push({
110
+ index: segmentIndex,
111
+ startTime: currentStart,
112
+ endTime: totalDuration,
113
+ duration: totalDuration - currentStart,
114
+ });
115
+ break;
116
+ }
117
+ // Find the closest silence point near the target end
118
+ let bestSplit = targetEnd;
119
+ let minDistance = Infinity;
120
+ for (const point of splitPoints) {
121
+ if (point > currentStart + minDuration && point < targetEnd + 30) {
122
+ const distance = Math.abs(point - targetEnd);
123
+ if (distance < minDistance) {
124
+ minDistance = distance;
125
+ bestSplit = point;
126
+ }
127
+ }
128
+ }
129
+ segments.push({
130
+ index: segmentIndex,
131
+ startTime: currentStart,
132
+ endTime: bestSplit,
133
+ duration: bestSplit - currentStart,
134
+ });
135
+ currentStart = bestSplit;
136
+ segmentIndex++;
137
+ }
138
+ // If no silences detected, use fixed segmentation
139
+ if (segments.length === 0) {
140
+ const fixedDuration = 60;
141
+ let start = 0;
142
+ let idx = 1;
143
+ while (start < totalDuration) {
144
+ const end = Math.min(start + fixedDuration, totalDuration);
145
+ segments.push({
146
+ index: idx,
147
+ startTime: start,
148
+ endTime: end,
149
+ duration: end - start,
150
+ });
151
+ start = end;
152
+ idx++;
153
+ }
154
+ }
155
+ return segments;
156
+ }
157
+ // Split video into segment
158
+ function splitVideo(inputPath, outputPath, startTime, duration) {
159
+ (0, child_process_1.execSync)(`ffmpeg -y -ss ${startTime} -i "${inputPath}" -t ${duration} -c copy "${outputPath}"`, { stdio: "ignore" });
160
+ }
161
+ // Extract audio from video segment
162
+ function extractAudio(videoPath, audioPath) {
163
+ (0, child_process_1.execSync)(`ffmpeg -y -i "${videoPath}" -vn -acodec libmp3lame -q:a 2 "${audioPath}"`, { stdio: "ignore" });
164
+ }
165
+ // Generate thumbnail from video segment
166
+ function generateThumbnail(videoPath, thumbnailPath) {
167
+ (0, child_process_1.execSync)(`ffmpeg -y -i "${videoPath}" -ss 0 -vframes 1 -vf "scale=640:-1" "${thumbnailPath}"`, { stdio: "ignore" });
168
+ }
169
+ // Transcribe audio using OpenAI Whisper API
170
+ async function transcribeAudio(audioPath, lang, openai) {
171
+ const audioFile = fs.createReadStream(audioPath);
172
+ const response = await openai.audio.transcriptions.create({
173
+ file: audioFile,
174
+ model: "whisper-1",
175
+ language: lang === "ja" ? "ja" : "en",
176
+ });
177
+ return response.text;
178
+ }
179
+ async function convertMovie(options) {
180
+ const { inputPath, lang, minSegmentDuration = 20, maxSegmentDuration = 120, } = options;
181
+ const videoPath = path.resolve(inputPath);
182
+ // Determine source language upfront (CLI option or default)
183
+ // For video transcription, we use the specified language directly
184
+ const sourceLang = lang && (0, lang_1.isValidLang)(lang) ? lang : "en";
185
+ if (!fs.existsSync(videoPath)) {
186
+ throw new Error(`File not found: ${videoPath}`);
187
+ }
188
+ // Check for required dependencies
189
+ (0, dependencies_1.checkDependencies)("movie");
190
+ // Check for OpenAI API key
191
+ const apiKey = process.env.OPENAI_API_KEY;
192
+ if (!apiKey) {
193
+ throw new Error("OPENAI_API_KEY environment variable is required for transcription");
194
+ }
195
+ const openai = new openai_1.default({ apiKey });
196
+ const ext = path.extname(videoPath);
197
+ const basename = path.basename(videoPath, ext);
198
+ // Scripts directory for MulmoScript and processing assets
199
+ const scriptsDir = options.outputDir || path.join("scripts", basename);
200
+ // Bundle output directory (same structure as other formats)
201
+ const bundleDir = path.join("output", basename, "mulmo_script");
202
+ // Create scripts directory
203
+ if (!fs.existsSync(scriptsDir)) {
204
+ fs.mkdirSync(scriptsDir, { recursive: true });
205
+ }
206
+ console.log(`Processing video: ${videoPath}`);
207
+ console.log(`Scripts directory: ${scriptsDir}`);
208
+ // Get video duration
209
+ console.log("Getting video duration...");
210
+ const totalDuration = getVideoDuration(videoPath);
211
+ console.log(` Total duration: ${Math.floor(totalDuration / 60)}m ${Math.floor(totalDuration % 60)}s`);
212
+ // Detect silence intervals
213
+ console.log("Detecting silence intervals...");
214
+ const silences = await detectSilence(videoPath);
215
+ console.log(` Found ${silences.length} silence intervals`);
216
+ // Calculate segments
217
+ console.log("Calculating segments...");
218
+ const segments = calculateSegments(totalDuration, silences, minSegmentDuration, maxSegmentDuration);
219
+ console.log(` Created ${segments.length} segments`);
220
+ // Process each segment
221
+ const beats = [];
222
+ const transcriptions = [];
223
+ for (const segment of segments) {
224
+ const segmentNum = segment.index;
225
+ const videoFile = `${segmentNum}.mp4`;
226
+ const audioFile = `${segmentNum}.mp3`;
227
+ const thumbnailFile = `${segmentNum}.jpg`;
228
+ const videoOutputPath = path.join(scriptsDir, videoFile);
229
+ const audioOutputPath = path.join(scriptsDir, audioFile);
230
+ const thumbnailOutputPath = path.join(scriptsDir, thumbnailFile);
231
+ console.log(`\nProcessing segment ${segmentNum}/${segments.length}...`);
232
+ // Split video (with caching)
233
+ if (!fs.existsSync(videoOutputPath)) {
234
+ console.log(` Splitting video...`);
235
+ splitVideo(videoPath, videoOutputPath, segment.startTime, segment.duration);
236
+ }
237
+ else {
238
+ console.log(` Using cached video`);
239
+ }
240
+ // Extract audio (with caching)
241
+ if (!fs.existsSync(audioOutputPath)) {
242
+ console.log(` Extracting audio...`);
243
+ extractAudio(videoOutputPath, audioOutputPath);
244
+ }
245
+ else {
246
+ console.log(` Using cached audio`);
247
+ }
248
+ // Generate thumbnail (with caching)
249
+ if (!fs.existsSync(thumbnailOutputPath)) {
250
+ console.log(` Generating thumbnail...`);
251
+ generateThumbnail(videoOutputPath, thumbnailOutputPath);
252
+ }
253
+ else {
254
+ console.log(` Using cached thumbnail`);
255
+ }
256
+ // Transcribe audio
257
+ console.log(` Transcribing audio...`);
258
+ const transcription = await transcribeAudio(audioOutputPath, sourceLang, openai);
259
+ transcriptions.push(transcription);
260
+ console.log(` Transcription: ${transcription.substring(0, 100)}...`);
261
+ beats.push({
262
+ text: transcription,
263
+ audioSources: {
264
+ [sourceLang]: audioFile,
265
+ },
266
+ multiLinguals: {
267
+ [sourceLang]: transcription,
268
+ },
269
+ videoSource: videoFile,
270
+ imageSource: thumbnailFile,
271
+ startTime: segment.startTime,
272
+ endTime: segment.endTime,
273
+ duration: segment.duration,
274
+ });
275
+ }
276
+ console.log(`\nSource language: ${sourceLang}`);
277
+ // Build MulmoScript with proper schema
278
+ // For video content, we use the `image` field with type: "movie"
279
+ const mulmoBeats = beats.map((beat) => ({
280
+ text: beat.text,
281
+ image: {
282
+ type: "movie",
283
+ source: {
284
+ kind: "path",
285
+ path: `./${beat.videoSource}`,
286
+ },
287
+ },
288
+ }));
289
+ const mulmoScript = {
290
+ $mulmocast: {
291
+ version: "1.1",
292
+ credit: "closing",
293
+ },
294
+ lang: sourceLang,
295
+ beats: mulmoBeats,
296
+ };
297
+ // Validate MulmoScript
298
+ const result = mulmocast_1.mulmoScriptSchema.safeParse(mulmoScript);
299
+ if (!result.success) {
300
+ console.error("MulmoScript validation failed:");
301
+ console.error(result.error.format());
302
+ throw new Error("Invalid MulmoScript generated");
303
+ }
304
+ // Write MulmoScript to scripts directory
305
+ const jsonPath = path.join(scriptsDir, "mulmo_script.json");
306
+ fs.writeFileSync(jsonPath, JSON.stringify(result.data, null, 2));
307
+ console.log(`\nMulmoScript saved to: ${jsonPath}`);
308
+ // Generate bundle with translations and TTS if requested
309
+ const shouldBundle = options.bundle ?? true; // Default to bundling for movie
310
+ const targetLangs = options.targetLangs ?? ["ja"]; // Default target language
311
+ let bundlePath;
312
+ if (shouldBundle) {
313
+ // Create bundle output directory
314
+ if (!fs.existsSync(bundleDir)) {
315
+ fs.mkdirSync(bundleDir, { recursive: true });
316
+ }
317
+ console.log(`Bundle directory: ${bundleDir}`);
318
+ // Prepare beat data for bundle generation
319
+ const bundleBeats = beats.map((beat, index) => ({
320
+ text: beat.text,
321
+ videoSource: beat.videoSource,
322
+ imageSource: beat.imageSource,
323
+ audioSource: beat.audioSources[sourceLang] || `${index + 1}.mp3`,
324
+ startTime: beat.startTime,
325
+ endTime: beat.endTime,
326
+ duration: beat.duration,
327
+ }));
328
+ await (0, movie_bundle_1.generateMovieBundle)({
329
+ scriptsDir,
330
+ outputDir: bundleDir,
331
+ sourceLang: sourceLang,
332
+ targetLangs,
333
+ beats: bundleBeats,
334
+ totalDuration,
335
+ });
336
+ bundlePath = path.join(bundleDir, "mulmo_view.json");
337
+ }
338
+ return {
339
+ mulmoScriptPath: jsonPath,
340
+ segmentCount: segments.length,
341
+ bundlePath,
342
+ };
343
+ }
344
+ async function main() {
345
+ // Load environment variables
346
+ const dotenv = await Promise.resolve().then(() => __importStar(require("dotenv")));
347
+ dotenv.config();
348
+ const argv = await (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
349
+ .usage("Usage: $0 <video-file> [options]")
350
+ .command("$0 <file>", "Convert video to MulmoScript", (yargs) => {
351
+ return yargs.positional("file", {
352
+ describe: "Video file to convert (mp4, mov, mkv, webm, avi)",
353
+ type: "string",
354
+ demandOption: true,
355
+ });
356
+ })
357
+ .options({
358
+ ...lang_1.langOption,
359
+ "min-segment": {
360
+ type: "number",
361
+ description: "Minimum segment duration in seconds",
362
+ default: 20,
363
+ },
364
+ "max-segment": {
365
+ type: "number",
366
+ description: "Maximum segment duration in seconds",
367
+ default: 120,
368
+ },
369
+ bundle: {
370
+ type: "boolean",
371
+ description: "Generate bundle with translations and TTS",
372
+ default: true,
373
+ },
374
+ "target-langs": {
375
+ type: "string",
376
+ description: "Target languages for translation (comma-separated)",
377
+ default: "ja",
378
+ },
379
+ })
380
+ .help()
381
+ .parse();
382
+ await convertMovie({
383
+ inputPath: argv.file,
384
+ lang: argv.l,
385
+ minSegmentDuration: argv["min-segment"],
386
+ maxSegmentDuration: argv["max-segment"],
387
+ bundle: argv.bundle,
388
+ targetLangs: argv["target-langs"].split(",").map((l) => l.trim()),
389
+ });
390
+ }
391
+ if (require.main === module) {
392
+ main().catch((error) => {
393
+ console.error("Error:", error.message);
394
+ process.exit(1);
395
+ });
396
+ }
397
+ //# sourceMappingURL=movie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"movie.js","sourceRoot":"","sources":["../../src/convert/movie.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8OA,oCA+MC;AA7bD,uCAAyB;AACzB,2CAA6B;AAC7B,iDAAgD;AAChD,kDAA0B;AAC1B,2CAAwC;AACxC,wCAA4E;AAC5E,wDAA0D;AAC1D,oDAA4B;AAC5B,yCAA8D;AAE9D,iDAAqD;AA2CrD,mCAAmC;AACnC,SAAS,gBAAgB,CAAC,SAAiB;IACzC,MAAM,MAAM,GAAG,IAAA,wBAAQ,EACrB,0FAA0F,SAAS,GAAG,EACtG,EAAE,QAAQ,EAAE,OAAO,EAAE,CACtB,CAAC;IACF,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,iDAAiD;AACjD,KAAK,UAAU,aAAa,CAC1B,SAAiB,EACjB,iBAAyB,CAAC,EAAE,EAC5B,qBAA6B,GAAG;IAEhC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,IAAI,YAAY,GAAkB,IAAI,CAAC;QAEvC,MAAM,MAAM,GAAG,IAAA,qBAAK,EAAC,QAAQ,EAAE;YAC7B,IAAI;YACJ,SAAS;YACT,KAAK;YACL,uBAAuB,cAAc,QAAQ,kBAAkB,EAAE;YACjE,IAAI;YACJ,MAAM;YACN,GAAG;SACJ,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAChC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAChC,mEAAmE;YACrE,CAAC;YAED,kDAAkD;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;gBAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;gBAEvD,IAAI,UAAU,EAAE,CAAC;oBACf,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3C,CAAC;gBACD,IAAI,QAAQ,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;oBACtC,QAAQ,CAAC,IAAI,CAAC;wBACZ,KAAK,EAAE,YAAY;wBACnB,GAAG,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;qBAC7B,CAAC,CAAC;oBACH,YAAY,GAAG,IAAI,CAAC;gBACtB,CAAC;YACH,CAAC;YAED,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0DAA0D;AAC1D,SAAS,iBAAiB,CACxB,aAAqB,EACrB,QAA2B,EAC3B,cAAsB,EAAE,EACxB,cAAsB,GAAG;IAEzB,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,kDAAkD;IAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAE/D,OAAO,YAAY,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;QAE7C,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;YAC/B,eAAe;YACf,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,YAAY;gBACnB,SAAS,EAAE,YAAY;gBACvB,OAAO,EAAE,aAAa;gBACtB,QAAQ,EAAE,aAAa,GAAG,YAAY;aACvC,CAAC,CAAC;YACH,MAAM;QACR,CAAC;QAED,qDAAqD;QACrD,IAAI,SAAS,GAAG,SAAS,CAAC;QAC1B,IAAI,WAAW,GAAG,QAAQ,CAAC;QAE3B,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YAChC,IAAI,KAAK,GAAG,YAAY,GAAG,WAAW,IAAI,KAAK,GAAG,SAAS,GAAG,EAAE,EAAE,CAAC;gBACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;gBAC7C,IAAI,QAAQ,GAAG,WAAW,EAAE,CAAC;oBAC3B,WAAW,GAAG,QAAQ,CAAC;oBACvB,SAAS,GAAG,KAAK,CAAC;gBACpB,CAAC;YACH,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC;YACZ,KAAK,EAAE,YAAY;YACnB,SAAS,EAAE,YAAY;YACvB,OAAO,EAAE,SAAS;YAClB,QAAQ,EAAE,SAAS,GAAG,YAAY;SACnC,CAAC,CAAC;QAEH,YAAY,GAAG,SAAS,CAAC;QACzB,YAAY,EAAE,CAAC;IACjB,CAAC;IAED,kDAAkD;IAClD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,aAAa,GAAG,EAAE,CAAC;QACzB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,OAAO,KAAK,GAAG,aAAa,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,aAAa,EAAE,aAAa,CAAC,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,GAAG;gBACV,SAAS,EAAE,KAAK;gBAChB,OAAO,EAAE,GAAG;gBACZ,QAAQ,EAAE,GAAG,GAAG,KAAK;aACtB,CAAC,CAAC;YACH,KAAK,GAAG,GAAG,CAAC;YACZ,GAAG,EAAE,CAAC;QACR,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,2BAA2B;AAC3B,SAAS,UAAU,CACjB,SAAiB,EACjB,UAAkB,EAClB,SAAiB,EACjB,QAAgB;IAEhB,IAAA,wBAAQ,EACN,iBAAiB,SAAS,QAAQ,SAAS,QAAQ,QAAQ,aAAa,UAAU,GAAG,EACrF,EAAE,KAAK,EAAE,QAAQ,EAAE,CACpB,CAAC;AACJ,CAAC;AAED,mCAAmC;AACnC,SAAS,YAAY,CAAC,SAAiB,EAAE,SAAiB;IACxD,IAAA,wBAAQ,EACN,iBAAiB,SAAS,oCAAoC,SAAS,GAAG,EAC1E,EAAE,KAAK,EAAE,QAAQ,EAAE,CACpB,CAAC;AACJ,CAAC;AAED,wCAAwC;AACxC,SAAS,iBAAiB,CAAC,SAAiB,EAAE,aAAqB;IACjE,IAAA,wBAAQ,EACN,iBAAiB,SAAS,0CAA0C,aAAa,GAAG,EACpF,EAAE,KAAK,EAAE,QAAQ,EAAE,CACpB,CAAC;AACJ,CAAC;AAED,4CAA4C;AAC5C,KAAK,UAAU,eAAe,CAC5B,SAAiB,EACjB,IAAY,EACZ,MAAc;IAEd,MAAM,SAAS,GAAG,EAAE,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAEjD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;QACxD,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,WAAW;QAClB,QAAQ,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;KACtC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,OAA4B;IAE5B,MAAM,EACJ,SAAS,EACT,IAAI,EACJ,kBAAkB,GAAG,EAAE,EACvB,kBAAkB,GAAG,GAAG,GACzB,GAAG,OAAO,CAAC;IACZ,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAE1C,4DAA4D;IAC5D,kEAAkE;IAClE,MAAM,UAAU,GAAkB,IAAI,IAAI,IAAA,kBAAW,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAE1E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,kCAAkC;IAClC,IAAA,gCAAiB,EAAC,OAAO,CAAC,CAAC;IAE3B,2BAA2B;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,gBAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAEtC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAE/C,0DAA0D;IAC1D,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvE,4DAA4D;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAEhE,2BAA2B;IAC3B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;IAEhD,qBAAqB;IACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,MAAM,aAAa,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAEvG,2BAA2B;IAC3B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,WAAW,QAAQ,CAAC,MAAM,oBAAoB,CAAC,CAAC;IAE5D,qBAAqB;IACrB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,iBAAiB,CAChC,aAAa,EACb,QAAQ,EACR,kBAAkB,EAClB,kBAAkB,CACnB,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,aAAa,QAAQ,CAAC,MAAM,WAAW,CAAC,CAAC;IAErD,uBAAuB;IACvB,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC;QACjC,MAAM,SAAS,GAAG,GAAG,UAAU,MAAM,CAAC;QACtC,MAAM,SAAS,GAAG,GAAG,UAAU,MAAM,CAAC;QACtC,MAAM,aAAa,GAAG,GAAG,UAAU,MAAM,CAAC;QAE1C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACzD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QACzD,MAAM,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QAEjE,OAAO,CAAC,GAAG,CAAC,wBAAwB,UAAU,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;QAExE,6BAA6B;QAC7B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,UAAU,CAAC,SAAS,EAAE,eAAe,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC9E,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACtC,CAAC;QAED,+BAA+B;QAC/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;YACrC,YAAY,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACtC,CAAC;QAED,oCAAoC;QACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;YACzC,iBAAiB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAC1C,CAAC;QAED,mBAAmB;QACnB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC,eAAe,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QACjF,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAEnC,OAAO,CAAC,GAAG,CAAC,oBAAoB,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAEtE,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,aAAa;YACnB,YAAY,EAAE;gBACZ,CAAC,UAAU,CAAC,EAAE,SAAS;aACxB;YACD,aAAa,EAAE;gBACb,CAAC,UAAU,CAAC,EAAE,aAAa;aAC5B;YACD,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,aAAa;YAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAC;IAEhD,uCAAuC;IACvC,iEAAiE;IACjE,MAAM,UAAU,GAAgB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE;YACL,IAAI,EAAE,OAAO;YACb,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE;aAC9B;SACF;KACF,CAAC,CAAC,CAAC;IAEJ,MAAM,WAAW,GAAqB;QACpC,UAAU,EAAE;YACV,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,SAAS;SAClB;QACD,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;KAClB,CAAC;IAEF,uBAAuB;IACvB,MAAM,MAAM,GAAG,6BAAiB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,yCAAyC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,mBAAmB,CAAC,CAAC;IAC5D,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;IAEnD,yDAAyD;IACzD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,gCAAgC;IAC7E,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,0BAA0B;IAE7E,IAAI,UAA8B,CAAC;IAEnC,IAAI,YAAY,EAAE,CAAC;QACjB,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC;QAE9C,0CAA0C;QAC1C,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC9C,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,GAAG,KAAK,GAAG,CAAC,MAAM;YAChE,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC,CAAC;QAEJ,MAAM,IAAA,kCAAmB,EAAC;YACxB,UAAU;YACV,SAAS,EAAE,SAAS;YACpB,UAAU,EAAE,UAAU;YACtB,WAAW;YACX,KAAK,EAAE,WAAW;YAClB,aAAa;SACd,CAAC,CAAC;QAEH,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IACvD,CAAC;IAED,OAAO;QACL,eAAe,EAAE,QAAQ;QACzB,YAAY,EAAE,QAAQ,CAAC,MAAM;QAC7B,UAAU;KACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,6BAA6B;IAC7B,MAAM,MAAM,GAAG,wDAAa,QAAQ,GAAC,CAAC;IACtC,MAAM,CAAC,MAAM,EAAE,CAAC;IAEhB,MAAM,IAAI,GAAG,MAAM,IAAA,eAAK,EAAC,IAAA,iBAAO,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;SAC5C,KAAK,CAAC,kCAAkC,CAAC;SACzC,OAAO,CAAC,WAAW,EAAE,8BAA8B,EAAE,CAAC,KAAK,EAAE,EAAE;QAC9D,OAAO,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE;YAC9B,QAAQ,EAAE,kDAAkD;YAC5D,IAAI,EAAE,QAAQ;YACd,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC,CAAC;SACD,OAAO,CAAC;QACP,GAAG,iBAAU;QACb,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,qCAAqC;YAClD,OAAO,EAAE,EAAE;SACZ;QACD,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,qCAAqC;YAClD,OAAO,EAAE,GAAG;SACb;QACD,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,2CAA2C;YACxD,OAAO,EAAE,IAAI;SACd;QACD,cAAc,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,oDAAoD;YACjE,OAAO,EAAE,IAAI;SACd;KACF,CAAC;SACD,IAAI,EAAE;SACN,KAAK,EAAE,CAAC;IAEX,MAAM,YAAY,CAAC;QACjB,SAAS,EAAE,IAAI,CAAC,IAAc;QAC9B,IAAI,EAAE,IAAI,CAAC,CAA8B;QACzC,kBAAkB,EAAE,IAAI,CAAC,aAAa,CAAC;QACvC,kBAAkB,EAAE,IAAI,CAAC,aAAa,CAAC;QACvC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,WAAW,EAAG,IAAI,CAAC,cAAc,CAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;KAC9E,CAAC,CAAC;AACL,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface BeatData {
2
+ text: string;
3
+ audioSources: Record<string, string>;
4
+ multiLinguals: Record<string, string>;
5
+ videoSource: string;
6
+ thumbnail: string;
7
+ startTime: number;
8
+ endTime: number;
9
+ duration: number;
10
+ }
11
+ export interface MulmoViewData {
12
+ lang: string;
13
+ totalDuration: number;
14
+ totalSegments: number;
15
+ beats: BeatData[];
16
+ }
17
+ export interface MovieBundleOptions {
18
+ scriptsDir: string;
19
+ outputDir: string;
20
+ sourceLang: string;
21
+ targetLangs: string[];
22
+ beats: Array<{
23
+ text: string;
24
+ videoSource: string;
25
+ imageSource: string;
26
+ audioSource: string;
27
+ startTime: number;
28
+ endTime: number;
29
+ duration: number;
30
+ }>;
31
+ totalDuration: number;
32
+ }
33
+ export declare function generateMovieBundle(options: MovieBundleOptions): Promise<MulmoViewData>;
34
+ //# sourceMappingURL=movie_bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"movie_bundle.d.ts","sourceRoot":"","sources":["../../src/convert/movie_bundle.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAyFD,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,aAAa,CAAC,CAiHxB"}
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.generateMovieBundle = generateMovieBundle;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const openai_1 = __importDefault(require("openai"));
43
+ const LANG_NAMES = {
44
+ en: "English",
45
+ ja: "Japanese",
46
+ fr: "French",
47
+ de: "German",
48
+ es: "Spanish",
49
+ zh: "Chinese",
50
+ ko: "Korean",
51
+ };
52
+ // Copy file if it doesn't exist in destination
53
+ function copyFileIfNeeded(srcPath, destPath) {
54
+ if (!fs.existsSync(destPath) && fs.existsSync(srcPath)) {
55
+ fs.copyFileSync(srcPath, destPath);
56
+ }
57
+ }
58
+ // Translate text using OpenAI with retry logic
59
+ async function translateText(text, fromLang, toLang, openai, maxRetries = 3) {
60
+ if (!text.trim()) {
61
+ return "";
62
+ }
63
+ const fromLangName = LANG_NAMES[fromLang] || fromLang;
64
+ const toLangName = LANG_NAMES[toLang] || toLang;
65
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
66
+ try {
67
+ const response = await openai.chat.completions.create({
68
+ model: "gpt-4o-mini",
69
+ messages: [
70
+ {
71
+ role: "system",
72
+ content: `Translate the given ${fromLangName} text to natural ${toLangName}. Only return the translated text, nothing else.`,
73
+ },
74
+ {
75
+ role: "user",
76
+ content: text,
77
+ },
78
+ ],
79
+ });
80
+ return response.choices[0]?.message?.content?.trim() || text;
81
+ }
82
+ catch (error) {
83
+ console.warn(`Translation attempt ${attempt}/${maxRetries} failed: ${error}`);
84
+ if (attempt === maxRetries) {
85
+ console.warn(`Translation failed after ${maxRetries} attempts, using original text`);
86
+ return text;
87
+ }
88
+ // Wait before retry (exponential backoff)
89
+ await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
90
+ }
91
+ }
92
+ return text;
93
+ }
94
+ // Generate TTS audio using OpenAI with retry logic
95
+ async function textToSpeech(text, outputPath, lang, openai, maxRetries = 3) {
96
+ if (!text.trim()) {
97
+ return;
98
+ }
99
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
100
+ try {
101
+ const response = await openai.audio.speech.create({
102
+ model: "tts-1",
103
+ voice: "alloy",
104
+ input: text,
105
+ });
106
+ const buffer = Buffer.from(await response.arrayBuffer());
107
+ fs.writeFileSync(outputPath, buffer);
108
+ return;
109
+ }
110
+ catch (error) {
111
+ console.warn(`TTS attempt ${attempt}/${maxRetries} failed: ${error}`);
112
+ if (attempt === maxRetries) {
113
+ console.error(`TTS generation failed for ${outputPath} after ${maxRetries} attempts`);
114
+ throw error;
115
+ }
116
+ // Wait before retry (exponential backoff)
117
+ await new Promise((resolve) => setTimeout(resolve, 1000 * attempt));
118
+ }
119
+ }
120
+ }
121
+ async function generateMovieBundle(options) {
122
+ const { scriptsDir, outputDir, sourceLang, targetLangs, beats, totalDuration } = options;
123
+ const apiKey = process.env.OPENAI_API_KEY;
124
+ if (!apiKey) {
125
+ throw new Error("OPENAI_API_KEY environment variable is required");
126
+ }
127
+ const openai = new openai_1.default({ apiKey });
128
+ const bundleBeats = [];
129
+ console.log(`\nGenerating bundle with ${beats.length} segments...`);
130
+ console.log(` Source: ${scriptsDir}`);
131
+ console.log(` Output: ${outputDir}`);
132
+ console.log(` Source language: ${sourceLang}`);
133
+ console.log(` Target languages: ${targetLangs.join(", ")}`);
134
+ for (let i = 0; i < beats.length; i++) {
135
+ const beat = beats[i];
136
+ const segmentNum = i + 1;
137
+ console.log(`\nProcessing segment ${segmentNum}/${beats.length}...`);
138
+ // Copy source assets to output directory
139
+ const srcVideoPath = path.join(scriptsDir, beat.videoSource);
140
+ const srcAudioPath = path.join(scriptsDir, beat.audioSource);
141
+ const srcThumbnailPath = path.join(scriptsDir, beat.imageSource);
142
+ const destVideoPath = path.join(outputDir, beat.videoSource);
143
+ const destAudioPath = path.join(outputDir, beat.audioSource);
144
+ const destThumbnailPath = path.join(outputDir, beat.imageSource);
145
+ console.log(` Copying assets...`);
146
+ copyFileIfNeeded(srcVideoPath, destVideoPath);
147
+ copyFileIfNeeded(srcAudioPath, destAudioPath);
148
+ copyFileIfNeeded(srcThumbnailPath, destThumbnailPath);
149
+ // Initialize audioSources and multiLinguals with source language
150
+ const audioSources = {
151
+ [sourceLang]: beat.audioSource,
152
+ };
153
+ const multiLinguals = {
154
+ [sourceLang]: beat.text,
155
+ };
156
+ // Process each target language
157
+ for (const targetLang of targetLangs) {
158
+ if (targetLang === sourceLang) {
159
+ continue;
160
+ }
161
+ const targetAudioFile = `${segmentNum}_${targetLang}.mp3`;
162
+ const targetAudioPath = path.join(outputDir, targetAudioFile);
163
+ // Check if translation/audio already exists (caching)
164
+ if (fs.existsSync(targetAudioPath)) {
165
+ console.log(` Using cached ${targetLang} audio`);
166
+ audioSources[targetLang] = targetAudioFile;
167
+ // Try to read cached translation from existing mulmo_view.json
168
+ const viewPath = path.join(outputDir, "mulmo_view.json");
169
+ if (fs.existsSync(viewPath)) {
170
+ try {
171
+ const existingView = JSON.parse(fs.readFileSync(viewPath, "utf-8"));
172
+ const existingBeat = existingView.beats?.[i];
173
+ if (existingBeat?.multiLinguals?.[targetLang]) {
174
+ multiLinguals[targetLang] = existingBeat.multiLinguals[targetLang];
175
+ continue;
176
+ }
177
+ }
178
+ catch {
179
+ // Ignore cache read errors
180
+ }
181
+ }
182
+ }
183
+ // Translate text
184
+ console.log(` Translating to ${targetLang}...`);
185
+ const translatedText = await translateText(beat.text, sourceLang, targetLang, openai);
186
+ multiLinguals[targetLang] = translatedText;
187
+ // Generate TTS audio if not cached
188
+ if (!fs.existsSync(targetAudioPath)) {
189
+ console.log(` Generating ${targetLang} audio...`);
190
+ await textToSpeech(translatedText, targetAudioPath, targetLang, openai);
191
+ }
192
+ audioSources[targetLang] = targetAudioFile;
193
+ }
194
+ bundleBeats.push({
195
+ text: beat.text,
196
+ audioSources,
197
+ multiLinguals,
198
+ videoSource: beat.videoSource,
199
+ thumbnail: beat.imageSource,
200
+ startTime: beat.startTime,
201
+ endTime: beat.endTime,
202
+ duration: beat.duration,
203
+ });
204
+ }
205
+ const mulmoView = {
206
+ lang: sourceLang,
207
+ totalDuration,
208
+ totalSegments: beats.length,
209
+ beats: bundleBeats,
210
+ };
211
+ // Write mulmo_view.json
212
+ const viewPath = path.join(outputDir, "mulmo_view.json");
213
+ fs.writeFileSync(viewPath, JSON.stringify(mulmoView, null, 2));
214
+ console.log(`\nBundle saved to: ${viewPath}`);
215
+ return mulmoView;
216
+ }
217
+ //# sourceMappingURL=movie_bundle.js.map