@studiomeyer/mcp-video 1.0.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.
Files changed (184) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
  3. package/.github/workflows/ci.yml +34 -0
  4. package/CHANGELOG.md +24 -0
  5. package/CONTRIBUTING.md +75 -0
  6. package/LICENSE +21 -0
  7. package/README.md +198 -0
  8. package/USAGE.md +144 -0
  9. package/dist/handlers/capcut.d.ts +6 -0
  10. package/dist/handlers/capcut.js +229 -0
  11. package/dist/handlers/capcut.js.map +1 -0
  12. package/dist/handlers/editing.d.ts +6 -0
  13. package/dist/handlers/editing.js +242 -0
  14. package/dist/handlers/editing.js.map +1 -0
  15. package/dist/handlers/index.d.ts +2 -0
  16. package/dist/handlers/index.js +33 -0
  17. package/dist/handlers/index.js.map +1 -0
  18. package/dist/handlers/post-production.d.ts +5 -0
  19. package/dist/handlers/post-production.js +109 -0
  20. package/dist/handlers/post-production.js.map +1 -0
  21. package/dist/handlers/smart-screenshot.d.ts +5 -0
  22. package/dist/handlers/smart-screenshot.js +83 -0
  23. package/dist/handlers/smart-screenshot.js.map +1 -0
  24. package/dist/handlers/tts.d.ts +5 -0
  25. package/dist/handlers/tts.js +83 -0
  26. package/dist/handlers/tts.js.map +1 -0
  27. package/dist/handlers/video.d.ts +5 -0
  28. package/dist/handlers/video.js +127 -0
  29. package/dist/handlers/video.js.map +1 -0
  30. package/dist/lib/dual-transport.d.ts +42 -0
  31. package/dist/lib/dual-transport.js +208 -0
  32. package/dist/lib/dual-transport.js.map +1 -0
  33. package/dist/lib/logger.d.ts +12 -0
  34. package/dist/lib/logger.js +42 -0
  35. package/dist/lib/logger.js.map +1 -0
  36. package/dist/lib/types.d.ts +16 -0
  37. package/dist/lib/types.js +15 -0
  38. package/dist/lib/types.js.map +1 -0
  39. package/dist/schemas/capcut.d.ts +608 -0
  40. package/dist/schemas/capcut.js +411 -0
  41. package/dist/schemas/capcut.js.map +1 -0
  42. package/dist/schemas/editing.d.ts +822 -0
  43. package/dist/schemas/editing.js +466 -0
  44. package/dist/schemas/editing.js.map +1 -0
  45. package/dist/schemas/index.d.ts +2366 -0
  46. package/dist/schemas/index.js +15 -0
  47. package/dist/schemas/index.js.map +1 -0
  48. package/dist/schemas/post-production.d.ts +379 -0
  49. package/dist/schemas/post-production.js +268 -0
  50. package/dist/schemas/post-production.js.map +1 -0
  51. package/dist/schemas/smart-screenshot.d.ts +127 -0
  52. package/dist/schemas/smart-screenshot.js +122 -0
  53. package/dist/schemas/smart-screenshot.js.map +1 -0
  54. package/dist/schemas/tts.d.ts +220 -0
  55. package/dist/schemas/tts.js +194 -0
  56. package/dist/schemas/tts.js.map +1 -0
  57. package/dist/schemas/video.d.ts +236 -0
  58. package/dist/schemas/video.js +210 -0
  59. package/dist/schemas/video.js.map +1 -0
  60. package/dist/server.d.ts +11 -0
  61. package/dist/server.js +239 -0
  62. package/dist/server.js.map +1 -0
  63. package/dist/server.test.d.ts +1 -0
  64. package/dist/server.test.js +87 -0
  65. package/dist/server.test.js.map +1 -0
  66. package/dist/tools/engine/audio-mixer.d.ts +40 -0
  67. package/dist/tools/engine/audio-mixer.js +169 -0
  68. package/dist/tools/engine/audio-mixer.js.map +1 -0
  69. package/dist/tools/engine/audio.d.ts +22 -0
  70. package/dist/tools/engine/audio.js +73 -0
  71. package/dist/tools/engine/audio.js.map +1 -0
  72. package/dist/tools/engine/beat-sync.d.ts +31 -0
  73. package/dist/tools/engine/beat-sync.js +270 -0
  74. package/dist/tools/engine/beat-sync.js.map +1 -0
  75. package/dist/tools/engine/capture.d.ts +12 -0
  76. package/dist/tools/engine/capture.js +290 -0
  77. package/dist/tools/engine/capture.js.map +1 -0
  78. package/dist/tools/engine/chroma-key.d.ts +27 -0
  79. package/dist/tools/engine/chroma-key.js +154 -0
  80. package/dist/tools/engine/chroma-key.js.map +1 -0
  81. package/dist/tools/engine/concat.d.ts +49 -0
  82. package/dist/tools/engine/concat.js +149 -0
  83. package/dist/tools/engine/concat.js.map +1 -0
  84. package/dist/tools/engine/cursor.d.ts +26 -0
  85. package/dist/tools/engine/cursor.js +185 -0
  86. package/dist/tools/engine/cursor.js.map +1 -0
  87. package/dist/tools/engine/easing.d.ts +15 -0
  88. package/dist/tools/engine/easing.js +100 -0
  89. package/dist/tools/engine/easing.js.map +1 -0
  90. package/dist/tools/engine/editing.d.ts +158 -0
  91. package/dist/tools/engine/editing.js +541 -0
  92. package/dist/tools/engine/editing.js.map +1 -0
  93. package/dist/tools/engine/encoder.d.ts +31 -0
  94. package/dist/tools/engine/encoder.js +154 -0
  95. package/dist/tools/engine/encoder.js.map +1 -0
  96. package/dist/tools/engine/index.d.ts +30 -0
  97. package/dist/tools/engine/index.js +23 -0
  98. package/dist/tools/engine/index.js.map +1 -0
  99. package/dist/tools/engine/lut-presets.d.ts +25 -0
  100. package/dist/tools/engine/lut-presets.js +141 -0
  101. package/dist/tools/engine/lut-presets.js.map +1 -0
  102. package/dist/tools/engine/narrated-video.d.ts +63 -0
  103. package/dist/tools/engine/narrated-video.js +163 -0
  104. package/dist/tools/engine/narrated-video.js.map +1 -0
  105. package/dist/tools/engine/scenes.d.ts +17 -0
  106. package/dist/tools/engine/scenes.js +223 -0
  107. package/dist/tools/engine/scenes.js.map +1 -0
  108. package/dist/tools/engine/smart-screenshot.d.ts +80 -0
  109. package/dist/tools/engine/smart-screenshot.js +744 -0
  110. package/dist/tools/engine/smart-screenshot.js.map +1 -0
  111. package/dist/tools/engine/social-format.d.ts +66 -0
  112. package/dist/tools/engine/social-format.js +107 -0
  113. package/dist/tools/engine/social-format.js.map +1 -0
  114. package/dist/tools/engine/template-renderer.d.ts +45 -0
  115. package/dist/tools/engine/template-renderer.js +233 -0
  116. package/dist/tools/engine/template-renderer.js.map +1 -0
  117. package/dist/tools/engine/templates.d.ts +87 -0
  118. package/dist/tools/engine/templates.js +272 -0
  119. package/dist/tools/engine/templates.js.map +1 -0
  120. package/dist/tools/engine/text-animations.d.ts +33 -0
  121. package/dist/tools/engine/text-animations.js +192 -0
  122. package/dist/tools/engine/text-animations.js.map +1 -0
  123. package/dist/tools/engine/text-overlay.d.ts +27 -0
  124. package/dist/tools/engine/text-overlay.js +84 -0
  125. package/dist/tools/engine/text-overlay.js.map +1 -0
  126. package/dist/tools/engine/tts.d.ts +54 -0
  127. package/dist/tools/engine/tts.js +186 -0
  128. package/dist/tools/engine/tts.js.map +1 -0
  129. package/dist/tools/engine/types.d.ts +166 -0
  130. package/dist/tools/engine/types.js +13 -0
  131. package/dist/tools/engine/types.js.map +1 -0
  132. package/dist/tools/engine/voice-effects.d.ts +18 -0
  133. package/dist/tools/engine/voice-effects.js +215 -0
  134. package/dist/tools/engine/voice-effects.js.map +1 -0
  135. package/dist/tools/index.d.ts +32 -0
  136. package/dist/tools/index.js +23 -0
  137. package/dist/tools/index.js.map +1 -0
  138. package/package.json +56 -0
  139. package/scripts/check-deps.js +39 -0
  140. package/src/handlers/capcut.ts +245 -0
  141. package/src/handlers/editing.ts +260 -0
  142. package/src/handlers/index.ts +34 -0
  143. package/src/handlers/post-production.ts +136 -0
  144. package/src/handlers/smart-screenshot.ts +86 -0
  145. package/src/handlers/tts.ts +103 -0
  146. package/src/handlers/video.ts +137 -0
  147. package/src/lib/dual-transport.ts +272 -0
  148. package/src/lib/logger.ts +59 -0
  149. package/src/lib/types.ts +25 -0
  150. package/src/schemas/capcut.ts +418 -0
  151. package/src/schemas/editing.ts +476 -0
  152. package/src/schemas/index.ts +15 -0
  153. package/src/schemas/post-production.ts +273 -0
  154. package/src/schemas/smart-screenshot.ts +122 -0
  155. package/src/schemas/tts.ts +197 -0
  156. package/src/schemas/video.ts +211 -0
  157. package/src/server.test.ts +99 -0
  158. package/src/server.ts +289 -0
  159. package/src/tools/engine/audio-mixer.ts +244 -0
  160. package/src/tools/engine/audio.ts +115 -0
  161. package/src/tools/engine/beat-sync.ts +356 -0
  162. package/src/tools/engine/capture.ts +360 -0
  163. package/src/tools/engine/chroma-key.ts +202 -0
  164. package/src/tools/engine/concat.ts +242 -0
  165. package/src/tools/engine/cursor.ts +222 -0
  166. package/src/tools/engine/easing.ts +120 -0
  167. package/src/tools/engine/editing.ts +809 -0
  168. package/src/tools/engine/encoder.ts +208 -0
  169. package/src/tools/engine/index.ts +33 -0
  170. package/src/tools/engine/lut-presets.ts +235 -0
  171. package/src/tools/engine/narrated-video.ts +267 -0
  172. package/src/tools/engine/scenes.ts +309 -0
  173. package/src/tools/engine/smart-screenshot.ts +923 -0
  174. package/src/tools/engine/social-format.ts +146 -0
  175. package/src/tools/engine/template-renderer.ts +294 -0
  176. package/src/tools/engine/templates.ts +370 -0
  177. package/src/tools/engine/text-animations.ts +282 -0
  178. package/src/tools/engine/text-overlay.ts +143 -0
  179. package/src/tools/engine/tts.ts +284 -0
  180. package/src/tools/engine/types.ts +191 -0
  181. package/src/tools/engine/voice-effects.ts +258 -0
  182. package/src/tools/index.ts +67 -0
  183. package/tsconfig.json +19 -0
  184. package/vitest.config.ts +7 -0
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Text overlay engine — animated titles, subtitles, watermarks
3
+ */
4
+ import { execFile } from 'child_process';
5
+ import * as fs from 'fs';
6
+ import { logger } from '../../lib/logger.js';
7
+ // ─── Position Resolver ──────────────────────────────────────────────
8
+ function resolvePosition(pos) {
9
+ switch (pos) {
10
+ case 'top': return { x: '(w-text_w)/2', y: 'h*0.08' };
11
+ case 'bottom': return { x: '(w-text_w)/2', y: 'h*0.88' };
12
+ case 'top-left': return { x: 'w*0.05', y: 'h*0.05' };
13
+ case 'top-right': return { x: 'w-text_w-w*0.05', y: 'h*0.05' };
14
+ case 'bottom-left': return { x: 'w*0.05', y: 'h-text_h-h*0.05' };
15
+ case 'bottom-right': return { x: 'w-text_w-w*0.05', y: 'h-text_h-h*0.05' };
16
+ default: return { x: '(w-text_w)/2', y: '(h-text_h)/2' };
17
+ }
18
+ }
19
+ // ─── Filter Builder ─────────────────────────────────────────────────
20
+ function buildDrawtextFilter(overlay, fontPath) {
21
+ const { text, position = 'center', fontSize = 48, fontColor = 'white', startTime, endTime, fadeIn = 0.5, fadeOut = 0.5, showBackground = false, backgroundColor = 'black@0.6', } = overlay;
22
+ const { x, y } = resolvePosition(position);
23
+ const fadeInEnd = startTime + fadeIn;
24
+ const fadeOutStart = endTime - fadeOut;
25
+ // Escape for ffmpeg
26
+ const escaped = text.replace(/'/g, "\\\\'").replace(/:/g, '\\:');
27
+ // Alpha expression: fade in → hold → fade out
28
+ const alpha = `if(lt(t\\,${startTime})\\,0\\,if(lt(t\\,${fadeInEnd})\\,(t-${startTime})/${fadeIn}\\,if(lt(t\\,${fadeOutStart})\\,1\\,if(lt(t\\,${endTime})\\,(${endTime}-t)/${fadeOut}\\,0))))`;
29
+ let filter = `drawtext=text='${escaped}':fontfile='${fontPath}':fontsize=${fontSize}:fontcolor=${fontColor}:x=${x}:y=${y}:alpha='${alpha}':enable='between(t,${startTime},${endTime})'`;
30
+ if (showBackground) {
31
+ filter += `:box=1:boxcolor=${backgroundColor}:boxborderw=12`;
32
+ }
33
+ return filter;
34
+ }
35
+ // ─── Main Function ──────────────────────────────────────────────────
36
+ export async function addTextOverlays(inputPath, outputPath, overlays) {
37
+ if (!fs.existsSync(inputPath))
38
+ throw new Error(`Input not found: ${inputPath}`);
39
+ if (overlays.length === 0)
40
+ throw new Error('No overlays provided');
41
+ const fontPath = findFont();
42
+ const filters = overlays.map((o) => buildDrawtextFilter(o, fontPath)).join(',');
43
+ logger.info(`Adding ${overlays.length} text overlay(s)`);
44
+ const args = [
45
+ '-y',
46
+ '-i', inputPath,
47
+ '-vf', filters,
48
+ '-c:a', 'copy',
49
+ '-c:v', 'libx264',
50
+ '-crf', '18',
51
+ '-pix_fmt', 'yuv420p',
52
+ '-movflags', '+faststart',
53
+ outputPath,
54
+ ];
55
+ await runFfmpeg(args);
56
+ logger.info(`Text overlays added: ${outputPath}`);
57
+ return outputPath;
58
+ }
59
+ // ─── Helpers ────────────────────────────────────────────────────────
60
+ function findFont() {
61
+ const candidates = [
62
+ '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf',
63
+ '/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf',
64
+ '/usr/share/fonts/truetype/ubuntu/Ubuntu-Bold.ttf',
65
+ ];
66
+ for (const f of candidates) {
67
+ if (fs.existsSync(f))
68
+ return f;
69
+ }
70
+ return '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf';
71
+ }
72
+ function runFfmpeg(args) {
73
+ return new Promise((resolve, reject) => {
74
+ execFile('ffmpeg', args, { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => {
75
+ if (error) {
76
+ logger.error(`ffmpeg failed: ${stderr}`);
77
+ reject(new Error(`ffmpeg failed: ${stderr || error.message}`));
78
+ return;
79
+ }
80
+ resolve(stdout);
81
+ });
82
+ });
83
+ }
84
+ //# sourceMappingURL=text-overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-overlay.js","sourceRoot":"","sources":["../../../src/tools/engine/text-overlay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Text-to-Speech Engine
3
+ * Primary: ElevenLabs (best quality, multilingual)
4
+ * Fallback: OpenAI TTS (reliable, already integrated)
5
+ *
6
+ * No extra npm dependencies — ElevenLabs uses native fetch,
7
+ * OpenAI uses the already-installed openai package
8
+ */
9
+ export type TTSProvider = 'elevenlabs' | 'openai';
10
+ export type ElevenLabsModel = 'eleven_multilingual_v2' | 'eleven_turbo_v2_5' | 'eleven_flash_v2_5';
11
+ export type ElevenLabsVoice = 'rachel' | 'sarah' | 'emily' | 'charlotte' | 'alice' | 'matilda' | 'lily' | 'brian' | 'adam' | 'daniel' | 'josh' | 'james' | 'liam' | 'chris' | 'george';
12
+ export type OpenAIVoice = 'alloy' | 'ash' | 'coral' | 'echo' | 'fable' | 'nova' | 'onyx' | 'sage' | 'shimmer';
13
+ export type OpenAIModel = 'tts-1' | 'tts-1-hd';
14
+ export interface TTSConfig {
15
+ /** Text to speak */
16
+ text: string;
17
+ /** Output path for the audio file */
18
+ outputPath: string;
19
+ /** TTS provider (default: elevenlabs) */
20
+ provider?: TTSProvider;
21
+ /** Language code (default: en) */
22
+ language?: string;
23
+ /** Speaking speed (default: 1.0) */
24
+ speed?: number;
25
+ /** ElevenLabs voice name (default: adam) */
26
+ elevenLabsVoice?: ElevenLabsVoice | string;
27
+ /** ElevenLabs model (default: eleven_multilingual_v2) */
28
+ elevenLabsModel?: ElevenLabsModel;
29
+ /** Voice stability 0-1 (default: 0.5) */
30
+ stability?: number;
31
+ /** Voice similarity 0-1 (default: 0.75) */
32
+ similarityBoost?: number;
33
+ /** OpenAI voice (default: onyx) */
34
+ openaiVoice?: OpenAIVoice;
35
+ /** OpenAI model (default: tts-1-hd) */
36
+ openaiModel?: OpenAIModel;
37
+ }
38
+ export interface TTSResult {
39
+ success: boolean;
40
+ audioPath: string;
41
+ provider: TTSProvider;
42
+ duration: number;
43
+ sizeBytes: number;
44
+ sizeMB: string;
45
+ text: string;
46
+ language: string;
47
+ }
48
+ export declare function generateSpeech(config: TTSConfig): Promise<TTSResult>;
49
+ export declare function listElevenLabsVoices(): Promise<Array<{
50
+ voice_id: string;
51
+ name: string;
52
+ category: string;
53
+ language: string;
54
+ }>>;
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Text-to-Speech Engine
3
+ * Primary: ElevenLabs (best quality, multilingual)
4
+ * Fallback: OpenAI TTS (reliable, already integrated)
5
+ *
6
+ * No extra npm dependencies — ElevenLabs uses native fetch,
7
+ * OpenAI uses the already-installed openai package
8
+ */
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import { logger } from '../../lib/logger.js';
12
+ import { getMediaDuration } from './audio.js';
13
+ // ─── ElevenLabs Voice IDs ───────────────────────────────────────────
14
+ const ELEVENLABS_VOICE_IDS = {
15
+ rachel: '21m00Tcm4TlvDq8ikWAM',
16
+ sarah: 'EXAVITQu4vr4xnSDxMaL',
17
+ emily: 'LcfcDJNUP1GQjkzn1xUU',
18
+ charlotte: 'XB0fDUnXU5powFXDhCwa',
19
+ alice: 'Xb7hH8MSUJpSbSDYk0k2',
20
+ matilda: 'XrExE9yKIg1WjnnlVkGX',
21
+ lily: 'pFZP5JQG7iQjIQuC4Bku',
22
+ brian: 'nPczCjzI2devNBz1zQrb',
23
+ adam: 'pNInz6obpgDQGcFmaJgB',
24
+ daniel: 'onwK4e9ZLuTAKqWW03F9',
25
+ josh: 'TxGEqnHWrfWFTfGW9XjX',
26
+ james: 'ZQe5CZNOzWyzPSCn5a3c',
27
+ liam: 'TX3LPaxmHKxFdv7VOQHJ',
28
+ chris: 'iP95p4xoKVk53GoZ742B',
29
+ george: 'JBFqnCBsd6RMkjVDRZzb',
30
+ };
31
+ // ─── Main TTS Function ─────────────────────────────────────────────
32
+ export async function generateSpeech(config) {
33
+ const { text, outputPath, provider = getDefaultProvider(), language = 'en', } = config;
34
+ // Ensure output dir exists
35
+ const outDir = path.dirname(outputPath);
36
+ if (!fs.existsSync(outDir))
37
+ fs.mkdirSync(outDir, { recursive: true });
38
+ // Ensure .mp3 extension
39
+ const finalPath = outputPath.endsWith('.mp3') ? outputPath : `${outputPath}.mp3`;
40
+ logger.info(`Generating speech (${provider}, ${language}, ${text.length} chars)`);
41
+ let audioPath;
42
+ try {
43
+ if (provider === 'elevenlabs') {
44
+ audioPath = await elevenLabsTTS(config, finalPath);
45
+ }
46
+ else {
47
+ audioPath = await openaiTTS(config, finalPath);
48
+ }
49
+ }
50
+ catch (error) {
51
+ // Fallback: try the other provider
52
+ const fallback = provider === 'elevenlabs' ? 'openai' : 'elevenlabs';
53
+ const msg = error instanceof Error ? error.message : String(error);
54
+ logger.warn(`${provider} TTS failed (${msg}), falling back to ${fallback}`);
55
+ try {
56
+ if (fallback === 'elevenlabs') {
57
+ audioPath = await elevenLabsTTS(config, finalPath);
58
+ }
59
+ else {
60
+ audioPath = await openaiTTS(config, finalPath);
61
+ }
62
+ }
63
+ catch (fallbackError) {
64
+ const fbMsg = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
65
+ throw new Error(`Both TTS providers failed. ${provider}: ${msg}, ${fallback}: ${fbMsg}`);
66
+ }
67
+ }
68
+ // Get audio stats
69
+ const stats = fs.statSync(audioPath);
70
+ let duration = 0;
71
+ try {
72
+ duration = await getMediaDuration(audioPath);
73
+ }
74
+ catch {
75
+ // ffprobe might not parse the file
76
+ }
77
+ logger.info(`Speech generated: ${audioPath} (${duration.toFixed(1)}s, ${(stats.size / 1024).toFixed(0)} KB)`);
78
+ return {
79
+ success: true,
80
+ audioPath,
81
+ provider,
82
+ duration,
83
+ sizeBytes: stats.size,
84
+ sizeMB: (stats.size / 1024 / 1024).toFixed(2),
85
+ text,
86
+ language,
87
+ };
88
+ }
89
+ // ─── ElevenLabs Implementation ──────────────────────────────────────
90
+ async function elevenLabsTTS(config, outputPath) {
91
+ const apiKey = process.env.ELEVENLABS_API_KEY;
92
+ if (!apiKey)
93
+ throw new Error('ELEVENLABS_API_KEY environment variable not set');
94
+ const voiceName = config.elevenLabsVoice ?? 'adam';
95
+ const voiceId = ELEVENLABS_VOICE_IDS[voiceName] ?? voiceName; // Allow raw voice IDs
96
+ const model = config.elevenLabsModel ?? 'eleven_multilingual_v2';
97
+ const language = config.language ?? 'en';
98
+ const url = `https://api.elevenlabs.io/v1/text-to-speech/${voiceId}?output_format=mp3_44100_128`;
99
+ const body = {
100
+ text: config.text,
101
+ model_id: model,
102
+ language_code: language,
103
+ voice_settings: {
104
+ stability: config.stability ?? 0.5,
105
+ similarity_boost: config.similarityBoost ?? 0.75,
106
+ style: 0.0,
107
+ speed: config.speed ?? 1.0,
108
+ use_speaker_boost: true,
109
+ },
110
+ };
111
+ logger.info(`ElevenLabs TTS: voice=${voiceName}, model=${model}, lang=${language}`);
112
+ const response = await fetch(url, {
113
+ method: 'POST',
114
+ headers: {
115
+ 'Content-Type': 'application/json',
116
+ 'xi-api-key': apiKey,
117
+ },
118
+ body: JSON.stringify(body),
119
+ });
120
+ if (!response.ok) {
121
+ const errorText = await response.text();
122
+ throw new Error(`ElevenLabs API ${response.status}: ${errorText}`);
123
+ }
124
+ const arrayBuffer = await response.arrayBuffer();
125
+ fs.writeFileSync(outputPath, Buffer.from(arrayBuffer));
126
+ return outputPath;
127
+ }
128
+ // ─── OpenAI Implementation ──────────────────────────────────────────
129
+ async function openaiTTS(config, outputPath) {
130
+ const apiKey = process.env.OPENAI_API_KEY;
131
+ if (!apiKey)
132
+ throw new Error('OPENAI_API_KEY environment variable not set');
133
+ const voice = config.openaiVoice ?? 'onyx';
134
+ const model = config.openaiModel ?? 'tts-1-hd';
135
+ const speed = config.speed ?? 1.0;
136
+ logger.info(`OpenAI TTS: voice=${voice}, model=${model}, speed=${speed}`);
137
+ // Use fetch directly (avoid OpenAI package version issues)
138
+ const response = await fetch('https://api.openai.com/v1/audio/speech', {
139
+ method: 'POST',
140
+ headers: {
141
+ 'Content-Type': 'application/json',
142
+ 'Authorization': `Bearer ${apiKey}`,
143
+ },
144
+ body: JSON.stringify({
145
+ model,
146
+ voice,
147
+ input: config.text,
148
+ response_format: 'mp3',
149
+ speed,
150
+ }),
151
+ });
152
+ if (!response.ok) {
153
+ const errorText = await response.text();
154
+ throw new Error(`OpenAI TTS API ${response.status}: ${errorText}`);
155
+ }
156
+ const arrayBuffer = await response.arrayBuffer();
157
+ fs.writeFileSync(outputPath, Buffer.from(arrayBuffer));
158
+ return outputPath;
159
+ }
160
+ // ─── List ElevenLabs Voices ─────────────────────────────────────────
161
+ export async function listElevenLabsVoices() {
162
+ const apiKey = process.env.ELEVENLABS_API_KEY;
163
+ if (!apiKey)
164
+ throw new Error('ELEVENLABS_API_KEY environment variable not set');
165
+ const response = await fetch('https://api.elevenlabs.io/v1/voices', {
166
+ headers: { 'xi-api-key': apiKey },
167
+ });
168
+ if (!response.ok)
169
+ throw new Error(`ElevenLabs API ${response.status}`);
170
+ const data = await response.json();
171
+ return data.voices.map((v) => ({
172
+ voice_id: v.voice_id,
173
+ name: v.name,
174
+ category: v.category,
175
+ language: v.labels?.language ?? 'unknown',
176
+ }));
177
+ }
178
+ // ─── Helper ─────────────────────────────────────────────────────────
179
+ function getDefaultProvider() {
180
+ if (process.env.ELEVENLABS_API_KEY)
181
+ return 'elevenlabs';
182
+ if (process.env.OPENAI_API_KEY)
183
+ return 'openai';
184
+ throw new Error('No TTS API key found. Set ELEVENLABS_API_KEY or OPENAI_API_KEY.');
185
+ }
186
+ //# sourceMappingURL=tts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/engine/tts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6D9C,uEAAuE;AAEvE,MAAM,oBAAoB,GAA2B;IACnD,MAAM,EAAE,sBAAsB;IAC9B,KAAK,EAAE,sBAAsB;IAC7B,KAAK,EAAE,sBAAsB;IAC7B,SAAS,EAAE,sBAAsB;IACjC,KAAK,EAAE,sBAAsB;IAC7B,OAAO,EAAE,sBAAsB;IAC/B,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,sBAAsB;IAC7B,IAAI,EAAE,sBAAsB;IAC5B,MAAM,EAAE,sBAAsB;IAC9B,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,sBAAsB;IAC7B,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,sBAAsB;IAC7B,MAAM,EAAE,sBAAsB;CAC/B,CAAC;AAEF,sEAAsE;AAEtE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAiB;IACpD,MAAM,EACJ,IAAI,EACJ,UAAU,EACV,QAAQ,GAAG,kBAAkB,EAAE,EAC/B,QAAQ,GAAG,IAAI,GAChB,GAAG,MAAM,CAAC;IAEX,2BAA2B;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtE,wBAAwB;IACxB,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,MAAM,CAAC;IAEjF,MAAM,CAAC,IAAI,CAAC,sBAAsB,QAAQ,KAAK,QAAQ,KAAK,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;IAElF,IAAI,SAAiB,CAAC;IAEtB,IAAI,CAAC;QACH,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YAC9B,SAAS,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mCAAmC;QACnC,MAAM,QAAQ,GAAG,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC;QACrE,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,gBAAgB,GAAG,sBAAsB,QAAQ,EAAE,CAAC,CAAC;QAE5E,IAAI,CAAC;YACH,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;gBAC9B,SAAS,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,SAAS,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAAC,OAAO,aAAa,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC7F,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,KAAK,GAAG,KAAK,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,qBAAqB,SAAS,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAE9G,OAAO;QACL,OAAO,EAAE,IAAI;QACb,SAAS;QACT,QAAQ;QACR,QAAQ;QACR,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7C,IAAI;QACJ,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,uEAAuE;AAEvE,KAAK,UAAU,aAAa,CAAC,MAAiB,EAAE,UAAkB;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAEhF,MAAM,SAAS,GAAG,MAAM,CAAC,eAAe,IAAI,MAAM,CAAC;IACnD,MAAM,OAAO,GAAG,oBAAoB,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC,CAAC,sBAAsB;IACpF,MAAM,KAAK,GAAG,MAAM,CAAC,eAAe,IAAI,wBAAwB,CAAC;IACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC;IAEzC,MAAM,GAAG,GAAG,+CAA+C,OAAO,8BAA8B,CAAC;IAEjG,MAAM,IAAI,GAA4B;QACpC,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE;YACd,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,GAAG;YAClC,gBAAgB,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;YAChD,KAAK,EAAE,GAAG;YACV,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG;YAC1B,iBAAiB,EAAE,IAAI;SACxB;KACF,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,yBAAyB,SAAS,WAAW,KAAK,UAAU,QAAQ,EAAE,CAAC,CAAC;IAEpF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,YAAY,EAAE,MAAM;SACrB;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAEvD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,uEAAuE;AAEvE,KAAK,UAAU,SAAS,CAAC,MAAiB,EAAE,UAAkB;IAC5D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAE5E,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,IAAI,UAAU,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC;IAElC,MAAM,CAAC,IAAI,CAAC,qBAAqB,KAAK,WAAW,KAAK,WAAW,KAAK,EAAE,CAAC,CAAC;IAE1E,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,wCAAwC,EAAE;QACrE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,UAAU,MAAM,EAAE;SACpC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,KAAK;YACL,KAAK;YACL,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,KAAK;SACN,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjD,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;IAEvD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,uEAAuE;AAEvE,MAAM,CAAC,KAAK,UAAU,oBAAoB;IAMxC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAEhF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,qCAAqC,EAAE;QAClE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEvE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAE/B,CAAC;IAEF,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,SAAS;KAC1C,CAAC,CAAC,CAAC;AACN,CAAC;AAED,uEAAuE;AAEvE,SAAS,kBAAkB;IACzB,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAAE,OAAO,YAAY,CAAC;IACxD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,QAAQ,CAAC;IAChD,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Type definitions for the Cinema Video Engine
3
+ */
4
+ export declare const VIEWPORTS: {
5
+ readonly desktop: {
6
+ readonly width: 1920;
7
+ readonly height: 1080;
8
+ };
9
+ readonly 'desktop-4k': {
10
+ readonly width: 3840;
11
+ readonly height: 2160;
12
+ };
13
+ readonly tablet: {
14
+ readonly width: 768;
15
+ readonly height: 1024;
16
+ };
17
+ readonly 'tablet-landscape': {
18
+ readonly width: 1024;
19
+ readonly height: 768;
20
+ };
21
+ readonly mobile: {
22
+ readonly width: 393;
23
+ readonly height: 852;
24
+ };
25
+ readonly 'mobile-landscape': {
26
+ readonly width: 852;
27
+ readonly height: 393;
28
+ };
29
+ };
30
+ export type ViewportPreset = keyof typeof VIEWPORTS;
31
+ export interface ViewportConfig {
32
+ width: number;
33
+ height: number;
34
+ }
35
+ export type EasingName = 'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'easeInQuart' | 'easeOutQuart' | 'easeInOutQuart' | 'easeInQuint' | 'easeOutQuint' | 'easeInOutQuint' | 'easeInOutSine' | 'cinematic' | 'showcase';
36
+ export interface SceneBase {
37
+ type: string;
38
+ }
39
+ export interface ScrollScene extends SceneBase {
40
+ type: 'scroll';
41
+ /** Target: 'bottom', 'top', pixel number, or CSS selector */
42
+ to: 'bottom' | 'top' | number | string;
43
+ /** Duration of the scroll in seconds */
44
+ duration: number;
45
+ /** Easing curve name (default: easeInOutCubic) */
46
+ easing?: EasingName;
47
+ }
48
+ export interface PauseScene extends SceneBase {
49
+ type: 'pause';
50
+ /** Duration in seconds */
51
+ duration: number;
52
+ }
53
+ export interface HoverScene extends SceneBase {
54
+ type: 'hover';
55
+ /** CSS selector of element to hover */
56
+ selector: string;
57
+ /** How long to hold the hover (seconds) */
58
+ duration: number;
59
+ /** Move cursor smoothly to element (default: true) */
60
+ animateCursor?: boolean;
61
+ }
62
+ export interface ClickScene extends SceneBase {
63
+ type: 'click';
64
+ /** CSS selector of element to click */
65
+ selector: string;
66
+ /** Wait strategy after click */
67
+ waitFor?: 'networkidle' | 'load' | number;
68
+ /** Pause after navigation (seconds, default: 1) */
69
+ pauseAfter?: number;
70
+ }
71
+ export interface TypeScene extends SceneBase {
72
+ type: 'type';
73
+ /** CSS selector of input field */
74
+ selector: string;
75
+ /** Text to type */
76
+ text: string;
77
+ /** Delay between keystrokes in ms (default: 80) */
78
+ delay?: number;
79
+ }
80
+ export interface WaitScene extends SceneBase {
81
+ type: 'wait';
82
+ /** CSS selector to wait for */
83
+ selector: string;
84
+ /** Max wait time in ms (default: 5000) */
85
+ timeout?: number;
86
+ }
87
+ export type Scene = ScrollScene | PauseScene | HoverScene | ClickScene | TypeScene | WaitScene;
88
+ export interface CursorConfig {
89
+ /** Show a visible cursor in the video (default: true) */
90
+ enabled: boolean;
91
+ /** Cursor style */
92
+ style?: 'dot' | 'arrow' | 'pointer' | 'custom';
93
+ /** Cursor color (CSS color string) */
94
+ color?: string;
95
+ /** Cursor size in px (default: 20) */
96
+ size?: number;
97
+ /** Show click animation (default: true) */
98
+ clickAnimation?: boolean;
99
+ }
100
+ export type VideoCodec = 'h264' | 'h265' | 'vp9';
101
+ export type VideoFormat = 'mp4' | 'webm';
102
+ export interface EncodingConfig {
103
+ /** Video codec (default: h264) */
104
+ codec?: VideoCodec;
105
+ /** Output format (default: mp4) */
106
+ format?: VideoFormat;
107
+ /** Constant Rate Factor — quality (0=lossless, 51=worst). Default: 18 */
108
+ crf?: number;
109
+ /** Encoding preset (default: slow for best quality) */
110
+ preset?: 'ultrafast' | 'fast' | 'medium' | 'slow' | 'veryslow';
111
+ /** Frames per second (default: 60) */
112
+ fps?: number;
113
+ }
114
+ export interface RecordingConfig {
115
+ /** URL to record */
116
+ url: string;
117
+ /** Output file path (without extension — auto-determined) */
118
+ outputPath: string;
119
+ /** Viewport preset or custom dimensions */
120
+ viewport?: ViewportPreset | ViewportConfig;
121
+ /** Frames per second (default: 60) */
122
+ fps?: number;
123
+ /** Scene definitions — if empty, does a default full-page scroll */
124
+ scenes?: Scene[];
125
+ /** Cursor configuration */
126
+ cursor?: CursorConfig;
127
+ /** Video encoding settings */
128
+ encoding?: EncodingConfig;
129
+ /** Dismiss cookie banners and overlays (default: true) */
130
+ dismissOverlays?: boolean;
131
+ /** Pre-scroll to trigger lazy loading (default: true) */
132
+ preloadContent?: boolean;
133
+ /** Device scale factor for retina (default: 1) */
134
+ deviceScaleFactor?: number;
135
+ /** Dark mode (default: false) */
136
+ darkMode?: boolean;
137
+ /** Custom user agent */
138
+ userAgent?: string;
139
+ /** Disable smooth scroll CSS to prevent double-easing (default: true) */
140
+ disableSmoothScroll?: boolean;
141
+ }
142
+ export interface RecordingResult {
143
+ success: boolean;
144
+ video: {
145
+ path: string;
146
+ format: string;
147
+ codec: string;
148
+ fps: number;
149
+ duration: number;
150
+ totalFrames: number;
151
+ resolution: {
152
+ width: number;
153
+ height: number;
154
+ };
155
+ sizeBytes: number;
156
+ sizeMB: string;
157
+ };
158
+ thumbnail?: {
159
+ path: string;
160
+ width: number;
161
+ height: number;
162
+ };
163
+ scenes: number;
164
+ url: string;
165
+ captureTime: string;
166
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Type definitions for the Cinema Video Engine
3
+ */
4
+ // ─── Viewport Presets ───────────────────────────────────────────────
5
+ export const VIEWPORTS = {
6
+ desktop: { width: 1920, height: 1080 },
7
+ 'desktop-4k': { width: 3840, height: 2160 },
8
+ tablet: { width: 768, height: 1024 },
9
+ 'tablet-landscape': { width: 1024, height: 768 },
10
+ mobile: { width: 393, height: 852 },
11
+ 'mobile-landscape': { width: 852, height: 393 },
12
+ };
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/tools/engine/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IACtC,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAC3C,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACpC,kBAAkB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAChD,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACnC,kBAAkB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACvC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Voice Effects Engine — 9 audio effects via FFmpeg filter chains.
3
+ *
4
+ * Effects: echo, reverb, deep, chipmunk, robot, whisper, radio, megaphone, underwater.
5
+ * Works on both audio files and video files (preserves video stream).
6
+ */
7
+ export type VoiceEffect = 'echo' | 'reverb' | 'deep' | 'chipmunk' | 'robot' | 'whisper' | 'radio' | 'megaphone' | 'underwater';
8
+ export interface VoiceEffectConfig {
9
+ inputPath: string;
10
+ outputPath: string;
11
+ /** Voice effect to apply */
12
+ effect: VoiceEffect;
13
+ /** Intensity 0.0-1.0 (default: 0.5). Controls how strong the effect is. */
14
+ intensity?: number;
15
+ }
16
+ export declare const ALL_VOICE_EFFECTS: VoiceEffect[];
17
+ export declare const VOICE_EFFECT_DESCRIPTIONS: Record<VoiceEffect, string>;
18
+ export declare function applyVoiceEffect(config: VoiceEffectConfig): Promise<string>;