@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,215 @@
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
+ import { execFile } from 'child_process';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import { logger } from '../../lib/logger.js';
11
+ export const ALL_VOICE_EFFECTS = [
12
+ 'echo', 'reverb', 'deep', 'chipmunk', 'robot',
13
+ 'whisper', 'radio', 'megaphone', 'underwater',
14
+ ];
15
+ export const VOICE_EFFECT_DESCRIPTIONS = {
16
+ echo: 'Indoor/outdoor echo with configurable delay',
17
+ reverb: 'Dense multi-tap reverb (hall-like)',
18
+ deep: 'Lower pitch — deep/bass voice',
19
+ chipmunk: 'Higher pitch — chipmunk/squeaky voice',
20
+ robot: 'Metallic robotic voice (phase zeroing)',
21
+ whisper: 'Breathy whisper effect with randomized phase',
22
+ radio: 'AM radio / telephone quality (bandpass)',
23
+ megaphone: 'Distorted megaphone with resonance',
24
+ underwater: 'Muffled underwater sound (heavy lowpass)',
25
+ };
26
+ // ─── Effect Filter Builders ─────────────────────────────────────────
27
+ function getEffectFilter(effect, intensity) {
28
+ const i = Math.max(0, Math.min(1, intensity));
29
+ switch (effect) {
30
+ case 'echo': {
31
+ // Scale delay and decay with intensity
32
+ const delay1 = Math.round(30 + i * 470); // 30-500ms
33
+ const delay2 = Math.round(60 + i * 940); // 60-1000ms
34
+ const decay1 = (0.2 + i * 0.3).toFixed(2); // 0.2-0.5
35
+ const decay2 = (0.1 + i * 0.2).toFixed(2); // 0.1-0.3
36
+ return { filter: `aecho=0.8:0.9:${delay1}|${delay2}:${decay1}|${decay2}` };
37
+ }
38
+ case 'reverb': {
39
+ // Dense multi-tap approximation of reverb
40
+ const taps = Math.round(3 + i * 7); // 3-10 taps
41
+ const delays = [];
42
+ const decays = [];
43
+ for (let t = 1; t <= taps; t++) {
44
+ delays.push(String(Math.round(t * 20)));
45
+ decays.push((0.6 - t * (0.5 / taps)).toFixed(2));
46
+ }
47
+ return { filter: `aecho=0.8:0.9:${delays.join('|')}:${decays.join('|')}` };
48
+ }
49
+ case 'deep': {
50
+ // Lower pitch: factor < 1.0 lowers pitch
51
+ // Intensity 0.0 → factor 0.95 (subtle), 1.0 → factor 0.5 (very deep)
52
+ const factor = 0.95 - i * 0.45; // 0.95 → 0.5
53
+ return { filter: '', needsComplexPitch: true, pitchFactor: factor };
54
+ }
55
+ case 'chipmunk': {
56
+ // Higher pitch: factor > 1.0 raises pitch
57
+ // Intensity 0.0 → factor 1.1 (subtle), 1.0 → factor 2.0 (extreme)
58
+ const factor = 1.1 + i * 0.9; // 1.1 → 2.0
59
+ return { filter: '', needsComplexPitch: true, pitchFactor: factor };
60
+ }
61
+ case 'robot': {
62
+ // Phase zeroing creates metallic robot effect
63
+ // At lower intensity, mix with short echo for metallic quality
64
+ if (i > 0.5) {
65
+ return { filter: "afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=512:overlap=0.75" };
66
+ }
67
+ // Lighter robot via very short echo
68
+ const delay = Math.round(3 + i * 10);
69
+ return { filter: `aecho=0.8:0.88:${delay}:${(0.3 + i * 0.3).toFixed(2)}` };
70
+ }
71
+ case 'whisper': {
72
+ if (i > 0.5) {
73
+ // Full whisper via phase randomization
74
+ return { filter: "afftfilt=real='hypot(re,im)*cos((random(0)*2-1)*2*3.14)':imag='hypot(re,im)*sin((random(1)*2-1)*2*3.14)':win_size=128:overlap=0.8" };
75
+ }
76
+ // Lighter whisper via filtering
77
+ const vol = (0.6 - i * 0.3).toFixed(2);
78
+ return { filter: `highpass=f=1000,lowpass=f=4000,volume=${vol}` };
79
+ }
80
+ case 'radio': {
81
+ // Bandpass gets narrower with intensity
82
+ const lowCut = Math.round(200 + i * 400); // 200-600 Hz
83
+ const highCut = Math.round(4000 - i * 2000); // 4000-2000 Hz
84
+ const crush = i > 0.5 ? `,acrusher=bits=${Math.round(12 - i * 6)}:mode=log:aa=1` : '';
85
+ return { filter: `highpass=f=${lowCut},lowpass=f=${highCut}${crush}` };
86
+ }
87
+ case 'megaphone': {
88
+ const bits = Math.round(12 - i * 6); // 12→6 bits
89
+ const vol = (1.5 + i * 1.0).toFixed(1);
90
+ return { filter: `highpass=f=500,lowpass=f=4000,acrusher=bits=${bits}:mode=log:aa=1:samples=1,aecho=0.8:0.88:10:${(0.3 + i * 0.3).toFixed(2)},volume=${vol}` };
91
+ }
92
+ case 'underwater': {
93
+ // Lowpass gets more extreme with intensity
94
+ const cutoff = Math.round(500 - i * 350); // 500→150 Hz
95
+ const vol = (0.9 - i * 0.3).toFixed(2);
96
+ const wobble = i > 0.3 ? `,flanger=delay=5:depth=${Math.round(1 + i * 4)}:speed=0.3` : '';
97
+ return { filter: `lowpass=f=${cutoff}${wobble},volume=${vol}` };
98
+ }
99
+ default:
100
+ throw new Error(`Unknown voice effect: ${effect}`);
101
+ }
102
+ }
103
+ // ─── Helpers ────────────────────────────────────────────────────────
104
+ function runFfmpeg(args, timeoutMs = 300_000) {
105
+ return new Promise((resolve, reject) => {
106
+ execFile('ffmpeg', args, { maxBuffer: 100 * 1024 * 1024, timeout: timeoutMs }, (error, stdout, stderr) => {
107
+ if (error) {
108
+ logger.error(`ffmpeg failed: ${stderr}`);
109
+ reject(new Error(`ffmpeg failed: ${stderr || error.message}`));
110
+ return;
111
+ }
112
+ resolve(stdout);
113
+ });
114
+ });
115
+ }
116
+ function runFfprobe(args) {
117
+ return new Promise((resolve, reject) => {
118
+ execFile('ffprobe', args, { maxBuffer: 10 * 1024 * 1024 }, (error, stdout) => {
119
+ if (error) {
120
+ reject(new Error(`ffprobe failed: ${error.message}`));
121
+ return;
122
+ }
123
+ resolve(stdout.trim());
124
+ });
125
+ });
126
+ }
127
+ function ensureDir(filePath) {
128
+ const dir = path.dirname(filePath);
129
+ if (!fs.existsSync(dir))
130
+ fs.mkdirSync(dir, { recursive: true });
131
+ }
132
+ function assertExists(filePath, label = 'File') {
133
+ if (!fs.existsSync(filePath))
134
+ throw new Error(`${label} not found: ${filePath}`);
135
+ }
136
+ function fileInfo(filePath) {
137
+ const stats = fs.statSync(filePath);
138
+ return `${(stats.size / 1024 / 1024).toFixed(2)} MB`;
139
+ }
140
+ async function hasVideoStream(filePath) {
141
+ try {
142
+ const result = await runFfprobe(['-v', 'quiet', '-select_streams', 'v', '-show_entries', 'stream=codec_type', '-of', 'csv=p=0', filePath]);
143
+ return result.length > 0;
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ }
149
+ async function getSampleRate(filePath) {
150
+ try {
151
+ const result = await runFfprobe(['-v', 'quiet', '-select_streams', 'a:0', '-show_entries', 'stream=sample_rate', '-of', 'csv=p=0', filePath]);
152
+ const rate = parseInt(result, 10);
153
+ return isNaN(rate) ? 44100 : rate;
154
+ }
155
+ catch {
156
+ return 44100;
157
+ }
158
+ }
159
+ /** Build chained atempo filters (each must be 0.5-100.0 range) */
160
+ function buildAtempoChain(speed) {
161
+ const filters = [];
162
+ let remaining = speed;
163
+ while (remaining > 2.0) {
164
+ filters.push('atempo=2.0');
165
+ remaining /= 2.0;
166
+ }
167
+ while (remaining < 0.5) {
168
+ filters.push('atempo=0.5');
169
+ remaining /= 0.5;
170
+ }
171
+ filters.push(`atempo=${remaining.toFixed(4)}`);
172
+ return filters.join(',');
173
+ }
174
+ // ─── Main Function ──────────────────────────────────────────────────
175
+ export async function applyVoiceEffect(config) {
176
+ const { inputPath, outputPath, effect, intensity = 0.5 } = config;
177
+ assertExists(inputPath, 'Input file');
178
+ ensureDir(outputPath);
179
+ const clampedIntensity = Math.max(0, Math.min(1, intensity));
180
+ logger.info(`Applying voice effect: ${effect} (intensity: ${clampedIntensity})`);
181
+ const effectData = getEffectFilter(effect, clampedIntensity);
182
+ const hasVideo = await hasVideoStream(inputPath);
183
+ if (effectData.needsComplexPitch && effectData.pitchFactor) {
184
+ // Pitch shifting requires asetrate + atempo combination
185
+ const sampleRate = await getSampleRate(inputPath);
186
+ const factor = effectData.pitchFactor;
187
+ const newRate = Math.round(sampleRate * factor);
188
+ const tempoCompensation = 1 / factor;
189
+ const audioFilter = `asetrate=${newRate},${buildAtempoChain(tempoCompensation)},aresample=${sampleRate}`;
190
+ const args = ['-y', '-i', inputPath];
191
+ if (hasVideo) {
192
+ args.push('-af', audioFilter, '-c:v', 'copy', '-movflags', '+faststart');
193
+ }
194
+ else {
195
+ args.push('-af', audioFilter);
196
+ }
197
+ args.push(outputPath);
198
+ await runFfmpeg(args);
199
+ }
200
+ else {
201
+ // Standard filter-based effects
202
+ const args = ['-y', '-i', inputPath];
203
+ if (hasVideo) {
204
+ args.push('-af', effectData.filter, '-c:v', 'copy', '-movflags', '+faststart');
205
+ }
206
+ else {
207
+ args.push('-af', effectData.filter);
208
+ }
209
+ args.push(outputPath);
210
+ await runFfmpeg(args);
211
+ }
212
+ logger.info(`Voice effect applied: ${effect} → ${outputPath} (${fileInfo(outputPath)})`);
213
+ return outputPath;
214
+ }
215
+ //# sourceMappingURL=voice-effects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice-effects.js","sourceRoot":"","sources":["../../../src/tools/engine/voice-effects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export { recordWebsite } from './engine/index.js';
2
+ export type { RecordingConfig, RecordingResult, Scene, ViewportPreset, EasingName } from './engine/index.js';
3
+ export { addBackgroundMusic } from './engine/audio.js';
4
+ export type { AddMusicConfig } from './engine/audio.js';
5
+ export { concatenateVideos, generateIntro } from './engine/concat.js';
6
+ export type { ConcatConfig, ConcatClip, IntroConfig, TransitionType } from './engine/concat.js';
7
+ export { convertToSocialFormat, convertToAllFormats, SOCIAL_FORMATS } from './engine/social-format.js';
8
+ export type { SocialFormat, CropStrategy, FormatConvertConfig } from './engine/social-format.js';
9
+ export { addTextOverlays } from './engine/text-overlay.js';
10
+ export type { TextOverlay, TextPosition } from './engine/text-overlay.js';
11
+ export { generateSpeech, listElevenLabsVoices } from './engine/tts.js';
12
+ export type { TTSConfig, TTSResult, TTSProvider, ElevenLabsVoice, OpenAIVoice } from './engine/tts.js';
13
+ export { createNarratedVideo } from './engine/narrated-video.js';
14
+ export type { NarratedVideoConfig, NarratedVideoResult, NarrationSegment } from './engine/narrated-video.js';
15
+ export { adjustVideoSpeed, applyColorGrade, applyVideoEffect, cropVideo, reverseClip, extractAudio, burnSubtitles, autoCaption, addKeyframeAnimation, composePip, addAudioDucking, } from './engine/editing.js';
16
+ export type { SpeedConfig, ColorGradeConfig, VideoEffect, EffectConfig, CropConfig, ReverseConfig, ExtractAudioConfig, BurnSubtitlesConfig, AutoCaptionConfig, AutoCaptionResult, Keyframe, KeyframeAnimationConfig, PipPosition, PipConfig, AudioDuckingConfig, } from './engine/editing.js';
17
+ export { applyLutPreset, listLutPresets, ALL_LUT_PRESETS, PRESET_DESCRIPTIONS } from './engine/lut-presets.js';
18
+ export type { LutPreset, LutPresetConfig } from './engine/lut-presets.js';
19
+ export { applyVoiceEffect, ALL_VOICE_EFFECTS, VOICE_EFFECT_DESCRIPTIONS } from './engine/voice-effects.js';
20
+ export type { VoiceEffect, VoiceEffectConfig } from './engine/voice-effects.js';
21
+ export { applyChromaKey } from './engine/chroma-key.js';
22
+ export type { ChromaKeyConfig } from './engine/chroma-key.js';
23
+ export { syncToBeats } from './engine/beat-sync.js';
24
+ export type { BeatSyncConfig, BeatSyncResult } from './engine/beat-sync.js';
25
+ export { animateText, ALL_TEXT_ANIMATIONS, TEXT_ANIMATION_DESCRIPTIONS } from './engine/text-animations.js';
26
+ export type { TextAnimation, TextAnimationConfig } from './engine/text-animations.js';
27
+ export { mixAudioTracks } from './engine/audio-mixer.js';
28
+ export type { AudioTrack, AudioMixConfig, AudioMixResult } from './engine/audio-mixer.js';
29
+ export { listTemplates, getTemplate, getTemplateSummaries, getTemplateCategories } from './engine/templates.js';
30
+ export type { VideoTemplate, TemplateCategory, TemplateSlot } from './engine/templates.js';
31
+ export { renderTemplate } from './engine/template-renderer.js';
32
+ export type { RenderTemplateConfig, RenderResult, TemplateAssets } from './engine/template-renderer.js';
@@ -0,0 +1,23 @@
1
+ // Core recording
2
+ export { recordWebsite } from './engine/index.js';
3
+ // Post-production
4
+ export { addBackgroundMusic } from './engine/audio.js';
5
+ export { concatenateVideos, generateIntro } from './engine/concat.js';
6
+ export { convertToSocialFormat, convertToAllFormats, SOCIAL_FORMATS } from './engine/social-format.js';
7
+ export { addTextOverlays } from './engine/text-overlay.js';
8
+ // TTS & Narration
9
+ export { generateSpeech, listElevenLabsVoices } from './engine/tts.js';
10
+ export { createNarratedVideo } from './engine/narrated-video.js';
11
+ // Editing (NEW — CapCut-tier features)
12
+ export { adjustVideoSpeed, applyColorGrade, applyVideoEffect, cropVideo, reverseClip, extractAudio, burnSubtitles, autoCaption, addKeyframeAnimation, composePip, addAudioDucking, } from './engine/editing.js';
13
+ // CapCut-tier engines
14
+ export { applyLutPreset, listLutPresets, ALL_LUT_PRESETS, PRESET_DESCRIPTIONS } from './engine/lut-presets.js';
15
+ export { applyVoiceEffect, ALL_VOICE_EFFECTS, VOICE_EFFECT_DESCRIPTIONS } from './engine/voice-effects.js';
16
+ export { applyChromaKey } from './engine/chroma-key.js';
17
+ export { syncToBeats } from './engine/beat-sync.js';
18
+ export { animateText, ALL_TEXT_ANIMATIONS, TEXT_ANIMATION_DESCRIPTIONS } from './engine/text-animations.js';
19
+ export { mixAudioTracks } from './engine/audio-mixer.js';
20
+ // Template engine
21
+ export { listTemplates, getTemplate, getTemplateSummaries, getTemplateCategories } from './engine/templates.js';
22
+ export { renderTemplate } from './engine/template-renderer.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,iBAAiB;AACjB,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,kBAAkB;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEvG,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG3D,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGjE,uCAAuC;AACvC,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,YAAY,EACZ,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,UAAU,EACV,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAe7B,sBAAsB;AACtB,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE/G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAE3G,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAE5G,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGzD,kBAAkB;AAClB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEhH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@studiomeyer/mcp-video",
3
+ "version": "1.0.0",
4
+ "description": "Cinema-grade video production MCP server — 8 tools for recording, editing, effects, captions, TTS, and smart screenshots. Zero-config, works with any MCP client.",
5
+ "type": "module",
6
+ "main": "dist/server.js",
7
+ "bin": {
8
+ "mcp-video": "./dist/server.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node dist/server.js",
13
+ "dev": "tsx src/server.ts",
14
+ "typecheck": "tsc --noEmit",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest",
17
+ "check": "node scripts/check-deps.js"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "video",
22
+ "ffmpeg",
23
+ "recording",
24
+ "editing",
25
+ "tts",
26
+ "screenshot",
27
+ "playwright",
28
+ "model-context-protocol",
29
+ "ai",
30
+ "claude"
31
+ ],
32
+ "author": "StudioMeyer <hello@studiomeyer.io>",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/studiomeyer-io/mcp-video.git"
37
+ },
38
+ "homepage": "https://github.com/studiomeyer-io/mcp-video",
39
+ "bugs": {
40
+ "url": "https://github.com/studiomeyer-io/mcp-video/issues"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ },
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.26.0",
47
+ "playwright": "^1.50.0",
48
+ "zod": "^3.22.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.10.0",
52
+ "tsx": "^4.7.0",
53
+ "typescript": "^5.3.0",
54
+ "vitest": "^1.6.0"
55
+ }
56
+ }
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Check system dependencies for mcp-video
4
+ */
5
+
6
+ import { execSync } from 'child_process';
7
+
8
+ const deps = [
9
+ { name: 'ffmpeg', cmd: 'ffmpeg -version', required: true },
10
+ { name: 'ffprobe', cmd: 'ffprobe -version', required: true },
11
+ { name: 'playwright browsers', cmd: 'npx playwright install --dry-run', required: false },
12
+ ];
13
+
14
+ let allOk = true;
15
+
16
+ for (const dep of deps) {
17
+ try {
18
+ const output = execSync(dep.cmd, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
19
+ const version = output.split('\n')[0].trim();
20
+ console.log(` ${dep.name}: ${version}`);
21
+ } catch {
22
+ if (dep.required) {
23
+ console.error(` ${dep.name}: NOT FOUND (required)`);
24
+ allOk = false;
25
+ } else {
26
+ console.warn(` ${dep.name}: not available (optional)`);
27
+ }
28
+ }
29
+ }
30
+
31
+ if (!allOk) {
32
+ console.error('\nMissing required dependencies. Install them:');
33
+ console.error(' Ubuntu/Debian: sudo apt install ffmpeg');
34
+ console.error(' macOS: brew install ffmpeg');
35
+ console.error(' Windows: choco install ffmpeg');
36
+ process.exit(1);
37
+ }
38
+
39
+ console.log('\nAll dependencies OK.');
@@ -0,0 +1,245 @@
1
+ /**
2
+ * CapCut-tier tool handlers — LUT Presets, Voice Effects, Chroma Key,
3
+ * Beat-Sync, Text Animations, Audio Mixer, Templates
4
+ */
5
+
6
+ import { jsonResponse, type ToolHandler } from '../lib/types.js';
7
+ import { logger } from '../lib/logger.js';
8
+ import { applyLutPreset, listLutPresets } from '../tools/engine/lut-presets.js';
9
+ import { applyVoiceEffect } from '../tools/engine/voice-effects.js';
10
+ import { applyChromaKey } from '../tools/engine/chroma-key.js';
11
+ import { syncToBeats } from '../tools/engine/beat-sync.js';
12
+ import { animateText } from '../tools/engine/text-animations.js';
13
+ import { mixAudioTracks } from '../tools/engine/audio-mixer.js';
14
+ import { getTemplateSummaries, getTemplate } from '../tools/engine/templates.js';
15
+ import { renderTemplate } from '../tools/engine/template-renderer.js';
16
+ import type { LutPreset } from '../tools/engine/lut-presets.js';
17
+ import type { VoiceEffect } from '../tools/engine/voice-effects.js';
18
+ import type { TextAnimation, TextPosition } from '../tools/engine/text-animations.js';
19
+ import type { AudioTrack } from '../tools/engine/audio-mixer.js';
20
+ import type { TemplateCategory } from '../tools/engine/templates.js';
21
+
22
+ export const capcutHandlers: Record<string, ToolHandler> = {
23
+
24
+ apply_lut_preset: async (args) => {
25
+ try {
26
+ const result = await applyLutPreset({
27
+ inputPath: args.inputPath,
28
+ outputPath: args.outputPath,
29
+ preset: args.preset as LutPreset,
30
+ intensity: args.intensity ?? 1.0,
31
+ });
32
+
33
+ const presets = listLutPresets();
34
+ const presetInfo = presets.find(p => p.name === args.preset);
35
+
36
+ return jsonResponse({
37
+ success: true,
38
+ outputPath: result,
39
+ preset: args.preset,
40
+ intensity: args.intensity ?? 1.0,
41
+ description: presetInfo?.description ?? '',
42
+ message: `Applied "${args.preset}" color grade (intensity: ${args.intensity ?? 1.0}).`,
43
+ availablePresets: presets.length,
44
+ });
45
+ } catch (error) {
46
+ const msg = error instanceof Error ? error.message : String(error);
47
+ logger.error(`apply_lut_preset failed: ${msg}`);
48
+ return jsonResponse({ success: false, error: msg }, true);
49
+ }
50
+ },
51
+
52
+ apply_voice_effect: async (args) => {
53
+ try {
54
+ const result = await applyVoiceEffect({
55
+ inputPath: args.inputPath,
56
+ outputPath: args.outputPath,
57
+ effect: args.effect as VoiceEffect,
58
+ intensity: args.intensity ?? 0.5,
59
+ });
60
+
61
+ return jsonResponse({
62
+ success: true,
63
+ outputPath: result,
64
+ effect: args.effect,
65
+ intensity: args.intensity ?? 0.5,
66
+ message: `Applied "${args.effect}" voice effect (intensity: ${args.intensity ?? 0.5}).`,
67
+ });
68
+ } catch (error) {
69
+ const msg = error instanceof Error ? error.message : String(error);
70
+ logger.error(`apply_voice_effect failed: ${msg}`);
71
+ return jsonResponse({ success: false, error: msg }, true);
72
+ }
73
+ },
74
+
75
+ apply_chroma_key: async (args) => {
76
+ try {
77
+ const result = await applyChromaKey({
78
+ inputPath: args.inputPath,
79
+ outputPath: args.outputPath,
80
+ background: args.background,
81
+ keyColor: args.keyColor ?? '00FF00',
82
+ similarity: args.similarity ?? 0.15,
83
+ blend: args.blend ?? 0.02,
84
+ despill: args.despill ?? true,
85
+ useColorkey: args.useColorkey ?? false,
86
+ });
87
+
88
+ return jsonResponse({
89
+ success: true,
90
+ outputPath: result,
91
+ keyColor: args.keyColor ?? '00FF00',
92
+ similarity: args.similarity ?? 0.15,
93
+ blend: args.blend ?? 0.02,
94
+ despill: args.despill ?? true,
95
+ mode: args.useColorkey ? 'colorkey (RGB)' : 'chromakey (YUV)',
96
+ message: `Chroma key applied — background replaced. Key color: #${args.keyColor ?? '00FF00'}.`,
97
+ });
98
+ } catch (error) {
99
+ const msg = error instanceof Error ? error.message : String(error);
100
+ logger.error(`apply_chroma_key failed: ${msg}`);
101
+ return jsonResponse({ success: false, error: msg }, true);
102
+ }
103
+ },
104
+
105
+ sync_to_beat: async (args) => {
106
+ try {
107
+ const result = await syncToBeats({
108
+ audioPath: args.audioPath,
109
+ clips: args.clips as string[],
110
+ outputPath: args.outputPath,
111
+ beatEffect: args.beatEffect ?? 'cut',
112
+ sensitivity: args.sensitivity ?? 0.6,
113
+ minBeatInterval: args.minBeatInterval ?? 0.3,
114
+ maxBeats: args.maxBeats ?? 50,
115
+ });
116
+
117
+ return jsonResponse({
118
+ success: true,
119
+ outputPath: result.outputPath,
120
+ beatsDetected: result.beatsDetected,
121
+ beatsUsed: result.beatsUsed,
122
+ duration: result.duration,
123
+ beatPositions: result.beatPositions.slice(0, 20), // First 20 for readability
124
+ message: `Beat-synced video: ${result.beatsUsed} cuts synced to ${result.beatsDetected} detected beats (${result.duration.toFixed(1)}s).`,
125
+ });
126
+ } catch (error) {
127
+ const msg = error instanceof Error ? error.message : String(error);
128
+ logger.error(`sync_to_beat failed: ${msg}`);
129
+ return jsonResponse({ success: false, error: msg }, true);
130
+ }
131
+ },
132
+
133
+ animate_text: async (args) => {
134
+ try {
135
+ const result = await animateText({
136
+ inputPath: args.inputPath,
137
+ outputPath: args.outputPath,
138
+ text: args.text,
139
+ animation: args.animation as TextAnimation,
140
+ startTime: args.startTime ?? 0,
141
+ duration: args.duration ?? 3,
142
+ fontSize: args.fontSize ?? 48,
143
+ fontColor: args.fontColor ?? 'FFFFFF',
144
+ position: (args.position as TextPosition) ?? 'center',
145
+ shadow: args.shadow ?? true,
146
+ });
147
+
148
+ return jsonResponse({
149
+ success: true,
150
+ outputPath: result,
151
+ animation: args.animation,
152
+ text: args.text,
153
+ startTime: args.startTime ?? 0,
154
+ duration: args.duration ?? 3,
155
+ message: `Animated text "${(args.text as string).substring(0, 30)}..." with ${args.animation} effect.`,
156
+ });
157
+ } catch (error) {
158
+ const msg = error instanceof Error ? error.message : String(error);
159
+ logger.error(`animate_text failed: ${msg}`);
160
+ return jsonResponse({ success: false, error: msg }, true);
161
+ }
162
+ },
163
+
164
+ mix_audio_tracks: async (args) => {
165
+ try {
166
+ const result = await mixAudioTracks({
167
+ tracks: args.tracks as AudioTrack[],
168
+ outputPath: args.outputPath,
169
+ autoDuck: args.autoDuck ?? false,
170
+ duckLevel: args.duckLevel ?? 0.2,
171
+ format: args.format ?? 'aac',
172
+ duration: args.duration,
173
+ });
174
+
175
+ return jsonResponse({
176
+ success: true,
177
+ outputPath: result.outputPath,
178
+ trackCount: result.trackCount,
179
+ ducking: result.ducking,
180
+ format: args.format ?? 'aac',
181
+ message: `Mixed ${result.trackCount} audio tracks${result.ducking ? ' with auto-ducking' : ''}.`,
182
+ });
183
+ } catch (error) {
184
+ const msg = error instanceof Error ? error.message : String(error);
185
+ logger.error(`mix_audio_tracks failed: ${msg}`);
186
+ return jsonResponse({ success: false, error: msg }, true);
187
+ }
188
+ },
189
+
190
+ list_video_templates: async (args) => {
191
+ try {
192
+ const category = args.category as TemplateCategory | undefined;
193
+ const summaries = getTemplateSummaries(category);
194
+
195
+ return jsonResponse({
196
+ success: true,
197
+ templates: summaries,
198
+ count: summaries.length,
199
+ categories: ['social-reel', 'product-demo', 'testimonial', 'before-after', 'slideshow', 'tutorial', 'announcement', 'promo'],
200
+ message: `Found ${summaries.length} templates${category ? ` in category "${category}"` : ''}.`,
201
+ });
202
+ } catch (error) {
203
+ const msg = error instanceof Error ? error.message : String(error);
204
+ logger.error(`list_video_templates failed: ${msg}`);
205
+ return jsonResponse({ success: false, error: msg }, true);
206
+ }
207
+ },
208
+
209
+ render_template: async (args) => {
210
+ try {
211
+ const result = await renderTemplate({
212
+ templateId: args.templateId,
213
+ outputPath: args.outputPath,
214
+ assets: {
215
+ clips: args.clips as Record<string, string>,
216
+ texts: args.texts as Record<string, string> | undefined,
217
+ musicPath: args.musicPath as string | undefined,
218
+ musicVolume: args.musicVolume as number | undefined,
219
+ },
220
+ colorGrade: args.colorGrade as string | undefined,
221
+ socialFormats: args.socialFormats ?? false,
222
+ });
223
+
224
+ // Get template details for the response
225
+ const template = getTemplate(args.templateId);
226
+
227
+ return jsonResponse({
228
+ success: true,
229
+ outputPath: result.outputPath,
230
+ template: result.template,
231
+ templateName: template?.name ?? result.template,
232
+ duration: `${result.duration}s`,
233
+ resolution: `${result.resolution.width}x${result.resolution.height}`,
234
+ clipsUsed: result.clipsUsed,
235
+ textsApplied: result.textsApplied,
236
+ socialVariants: result.socialVariants,
237
+ message: `Rendered "${template?.name ?? result.template}": ${result.clipsUsed} clips, ${result.textsApplied} text animations, ${result.duration}s.`,
238
+ });
239
+ } catch (error) {
240
+ const msg = error instanceof Error ? error.message : String(error);
241
+ logger.error(`render_template failed: ${msg}`);
242
+ return jsonResponse({ success: false, error: msg }, true);
243
+ }
244
+ },
245
+ };