@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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/workflows/ci.yml +34 -0
- package/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +75 -0
- package/LICENSE +21 -0
- package/README.md +198 -0
- package/USAGE.md +144 -0
- package/dist/handlers/capcut.d.ts +6 -0
- package/dist/handlers/capcut.js +229 -0
- package/dist/handlers/capcut.js.map +1 -0
- package/dist/handlers/editing.d.ts +6 -0
- package/dist/handlers/editing.js +242 -0
- package/dist/handlers/editing.js.map +1 -0
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +33 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/post-production.d.ts +5 -0
- package/dist/handlers/post-production.js +109 -0
- package/dist/handlers/post-production.js.map +1 -0
- package/dist/handlers/smart-screenshot.d.ts +5 -0
- package/dist/handlers/smart-screenshot.js +83 -0
- package/dist/handlers/smart-screenshot.js.map +1 -0
- package/dist/handlers/tts.d.ts +5 -0
- package/dist/handlers/tts.js +83 -0
- package/dist/handlers/tts.js.map +1 -0
- package/dist/handlers/video.d.ts +5 -0
- package/dist/handlers/video.js +127 -0
- package/dist/handlers/video.js.map +1 -0
- package/dist/lib/dual-transport.d.ts +42 -0
- package/dist/lib/dual-transport.js +208 -0
- package/dist/lib/dual-transport.js.map +1 -0
- package/dist/lib/logger.d.ts +12 -0
- package/dist/lib/logger.js +42 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/types.d.ts +16 -0
- package/dist/lib/types.js +15 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/schemas/capcut.d.ts +608 -0
- package/dist/schemas/capcut.js +411 -0
- package/dist/schemas/capcut.js.map +1 -0
- package/dist/schemas/editing.d.ts +822 -0
- package/dist/schemas/editing.js +466 -0
- package/dist/schemas/editing.js.map +1 -0
- package/dist/schemas/index.d.ts +2366 -0
- package/dist/schemas/index.js +15 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/post-production.d.ts +379 -0
- package/dist/schemas/post-production.js +268 -0
- package/dist/schemas/post-production.js.map +1 -0
- package/dist/schemas/smart-screenshot.d.ts +127 -0
- package/dist/schemas/smart-screenshot.js +122 -0
- package/dist/schemas/smart-screenshot.js.map +1 -0
- package/dist/schemas/tts.d.ts +220 -0
- package/dist/schemas/tts.js +194 -0
- package/dist/schemas/tts.js.map +1 -0
- package/dist/schemas/video.d.ts +236 -0
- package/dist/schemas/video.js +210 -0
- package/dist/schemas/video.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +239 -0
- package/dist/server.js.map +1 -0
- package/dist/server.test.d.ts +1 -0
- package/dist/server.test.js +87 -0
- package/dist/server.test.js.map +1 -0
- package/dist/tools/engine/audio-mixer.d.ts +40 -0
- package/dist/tools/engine/audio-mixer.js +169 -0
- package/dist/tools/engine/audio-mixer.js.map +1 -0
- package/dist/tools/engine/audio.d.ts +22 -0
- package/dist/tools/engine/audio.js +73 -0
- package/dist/tools/engine/audio.js.map +1 -0
- package/dist/tools/engine/beat-sync.d.ts +31 -0
- package/dist/tools/engine/beat-sync.js +270 -0
- package/dist/tools/engine/beat-sync.js.map +1 -0
- package/dist/tools/engine/capture.d.ts +12 -0
- package/dist/tools/engine/capture.js +290 -0
- package/dist/tools/engine/capture.js.map +1 -0
- package/dist/tools/engine/chroma-key.d.ts +27 -0
- package/dist/tools/engine/chroma-key.js +154 -0
- package/dist/tools/engine/chroma-key.js.map +1 -0
- package/dist/tools/engine/concat.d.ts +49 -0
- package/dist/tools/engine/concat.js +149 -0
- package/dist/tools/engine/concat.js.map +1 -0
- package/dist/tools/engine/cursor.d.ts +26 -0
- package/dist/tools/engine/cursor.js +185 -0
- package/dist/tools/engine/cursor.js.map +1 -0
- package/dist/tools/engine/easing.d.ts +15 -0
- package/dist/tools/engine/easing.js +100 -0
- package/dist/tools/engine/easing.js.map +1 -0
- package/dist/tools/engine/editing.d.ts +158 -0
- package/dist/tools/engine/editing.js +541 -0
- package/dist/tools/engine/editing.js.map +1 -0
- package/dist/tools/engine/encoder.d.ts +31 -0
- package/dist/tools/engine/encoder.js +154 -0
- package/dist/tools/engine/encoder.js.map +1 -0
- package/dist/tools/engine/index.d.ts +30 -0
- package/dist/tools/engine/index.js +23 -0
- package/dist/tools/engine/index.js.map +1 -0
- package/dist/tools/engine/lut-presets.d.ts +25 -0
- package/dist/tools/engine/lut-presets.js +141 -0
- package/dist/tools/engine/lut-presets.js.map +1 -0
- package/dist/tools/engine/narrated-video.d.ts +63 -0
- package/dist/tools/engine/narrated-video.js +163 -0
- package/dist/tools/engine/narrated-video.js.map +1 -0
- package/dist/tools/engine/scenes.d.ts +17 -0
- package/dist/tools/engine/scenes.js +223 -0
- package/dist/tools/engine/scenes.js.map +1 -0
- package/dist/tools/engine/smart-screenshot.d.ts +80 -0
- package/dist/tools/engine/smart-screenshot.js +744 -0
- package/dist/tools/engine/smart-screenshot.js.map +1 -0
- package/dist/tools/engine/social-format.d.ts +66 -0
- package/dist/tools/engine/social-format.js +107 -0
- package/dist/tools/engine/social-format.js.map +1 -0
- package/dist/tools/engine/template-renderer.d.ts +45 -0
- package/dist/tools/engine/template-renderer.js +233 -0
- package/dist/tools/engine/template-renderer.js.map +1 -0
- package/dist/tools/engine/templates.d.ts +87 -0
- package/dist/tools/engine/templates.js +272 -0
- package/dist/tools/engine/templates.js.map +1 -0
- package/dist/tools/engine/text-animations.d.ts +33 -0
- package/dist/tools/engine/text-animations.js +192 -0
- package/dist/tools/engine/text-animations.js.map +1 -0
- package/dist/tools/engine/text-overlay.d.ts +27 -0
- package/dist/tools/engine/text-overlay.js +84 -0
- package/dist/tools/engine/text-overlay.js.map +1 -0
- package/dist/tools/engine/tts.d.ts +54 -0
- package/dist/tools/engine/tts.js +186 -0
- package/dist/tools/engine/tts.js.map +1 -0
- package/dist/tools/engine/types.d.ts +166 -0
- package/dist/tools/engine/types.js +13 -0
- package/dist/tools/engine/types.js.map +1 -0
- package/dist/tools/engine/voice-effects.d.ts +18 -0
- package/dist/tools/engine/voice-effects.js +215 -0
- package/dist/tools/engine/voice-effects.js.map +1 -0
- package/dist/tools/index.d.ts +32 -0
- package/dist/tools/index.js +23 -0
- package/dist/tools/index.js.map +1 -0
- package/package.json +56 -0
- package/scripts/check-deps.js +39 -0
- package/src/handlers/capcut.ts +245 -0
- package/src/handlers/editing.ts +260 -0
- package/src/handlers/index.ts +34 -0
- package/src/handlers/post-production.ts +136 -0
- package/src/handlers/smart-screenshot.ts +86 -0
- package/src/handlers/tts.ts +103 -0
- package/src/handlers/video.ts +137 -0
- package/src/lib/dual-transport.ts +272 -0
- package/src/lib/logger.ts +59 -0
- package/src/lib/types.ts +25 -0
- package/src/schemas/capcut.ts +418 -0
- package/src/schemas/editing.ts +476 -0
- package/src/schemas/index.ts +15 -0
- package/src/schemas/post-production.ts +273 -0
- package/src/schemas/smart-screenshot.ts +122 -0
- package/src/schemas/tts.ts +197 -0
- package/src/schemas/video.ts +211 -0
- package/src/server.test.ts +99 -0
- package/src/server.ts +289 -0
- package/src/tools/engine/audio-mixer.ts +244 -0
- package/src/tools/engine/audio.ts +115 -0
- package/src/tools/engine/beat-sync.ts +356 -0
- package/src/tools/engine/capture.ts +360 -0
- package/src/tools/engine/chroma-key.ts +202 -0
- package/src/tools/engine/concat.ts +242 -0
- package/src/tools/engine/cursor.ts +222 -0
- package/src/tools/engine/easing.ts +120 -0
- package/src/tools/engine/editing.ts +809 -0
- package/src/tools/engine/encoder.ts +208 -0
- package/src/tools/engine/index.ts +33 -0
- package/src/tools/engine/lut-presets.ts +235 -0
- package/src/tools/engine/narrated-video.ts +267 -0
- package/src/tools/engine/scenes.ts +309 -0
- package/src/tools/engine/smart-screenshot.ts +923 -0
- package/src/tools/engine/social-format.ts +146 -0
- package/src/tools/engine/template-renderer.ts +294 -0
- package/src/tools/engine/templates.ts +370 -0
- package/src/tools/engine/text-animations.ts +282 -0
- package/src/tools/engine/text-overlay.ts +143 -0
- package/src/tools/engine/tts.ts +284 -0
- package/src/tools/engine/types.ts +191 -0
- package/src/tools/engine/voice-effects.ts +258 -0
- package/src/tools/index.ts +67 -0
- package/tsconfig.json +19 -0
- 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
|
+
};
|