@synthetic-ai/premiere-mcp 2.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/CHANGELOG.md +73 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/cep-plugin/.debug +8 -0
- package/cep-plugin/CSInterface.js +70 -0
- package/cep-plugin/CSXS/manifest.xml +49 -0
- package/cep-plugin/host.jsx +7 -0
- package/cep-plugin/index.html +419 -0
- package/cep-plugin/main.js +327 -0
- package/cep-plugin/premiere.jsx +24947 -0
- package/cep-plugin/synthetic-logo.png +0 -0
- package/dist/bridge/file-bridge.d.ts +29 -0
- package/dist/bridge/file-bridge.js +145 -0
- package/dist/bridge/script-builder.d.ts +19 -0
- package/dist/bridge/script-builder.js +408 -0
- package/dist/http-server.d.ts +21 -0
- package/dist/http-server.js +140 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +70 -0
- package/dist/resources/extendscript-reference.d.ts +2 -0
- package/dist/resources/extendscript-reference.js +219 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +276 -0
- package/dist/tools/advanced.d.ts +530 -0
- package/dist/tools/advanced.js +923 -0
- package/dist/tools/audio-advanced.d.ts +847 -0
- package/dist/tools/audio-advanced.js +1653 -0
- package/dist/tools/audio.d.ts +84 -0
- package/dist/tools/audio.js +123 -0
- package/dist/tools/captions.d.ts +30 -0
- package/dist/tools/captions.js +73 -0
- package/dist/tools/clipboard.d.ts +153 -0
- package/dist/tools/clipboard.js +381 -0
- package/dist/tools/color-advanced.d.ts +821 -0
- package/dist/tools/color-advanced.js +772 -0
- package/dist/tools/discovery.d.ts +128 -0
- package/dist/tools/discovery.js +445 -0
- package/dist/tools/effects.d.ts +211 -0
- package/dist/tools/effects.js +554 -0
- package/dist/tools/export-presets.d.ts +333 -0
- package/dist/tools/export-presets.js +490 -0
- package/dist/tools/export.d.ts +320 -0
- package/dist/tools/export.js +618 -0
- package/dist/tools/health.d.ts +9 -0
- package/dist/tools/health.js +25 -0
- package/dist/tools/inspection.d.ts +179 -0
- package/dist/tools/inspection.js +1089 -0
- package/dist/tools/keyframes.d.ts +253 -0
- package/dist/tools/keyframes.js +611 -0
- package/dist/tools/markers.d.ts +117 -0
- package/dist/tools/markers.js +206 -0
- package/dist/tools/media.d.ts +297 -0
- package/dist/tools/media.js +493 -0
- package/dist/tools/metadata.d.ts +178 -0
- package/dist/tools/metadata.js +278 -0
- package/dist/tools/multicam.d.ts +199 -0
- package/dist/tools/multicam.js +212 -0
- package/dist/tools/playback.d.ts +34 -0
- package/dist/tools/playback.js +63 -0
- package/dist/tools/playhead.d.ts +77 -0
- package/dist/tools/playhead.js +185 -0
- package/dist/tools/project-manager.d.ts +65 -0
- package/dist/tools/project-manager.js +81 -0
- package/dist/tools/project.d.ts +390 -0
- package/dist/tools/project.js +596 -0
- package/dist/tools/scripting.d.ts +98 -0
- package/dist/tools/scripting.js +434 -0
- package/dist/tools/selection.d.ts +120 -0
- package/dist/tools/selection.js +334 -0
- package/dist/tools/sequence-advanced.d.ts +84 -0
- package/dist/tools/sequence-advanced.js +471 -0
- package/dist/tools/sequence-settings.d.ts +397 -0
- package/dist/tools/sequence-settings.js +967 -0
- package/dist/tools/sequence.d.ts +211 -0
- package/dist/tools/sequence.js +378 -0
- package/dist/tools/source-monitor.d.ts +95 -0
- package/dist/tools/source-monitor.js +180 -0
- package/dist/tools/text.d.ts +97 -0
- package/dist/tools/text.js +159 -0
- package/dist/tools/timeline.d.ts +265 -0
- package/dist/tools/timeline.js +575 -0
- package/dist/tools/track-management.d.ts +482 -0
- package/dist/tools/track-management.js +787 -0
- package/dist/tools/track-targeting.d.ts +666 -0
- package/dist/tools/track-targeting.js +1318 -0
- package/dist/tools/tracks.d.ts +90 -0
- package/dist/tools/tracks.js +183 -0
- package/dist/tools/transitions-motion.d.ts +788 -0
- package/dist/tools/transitions-motion.js +680 -0
- package/dist/tools/transitions.d.ts +124 -0
- package/dist/tools/transitions.js +267 -0
- package/dist/tools/utility.d.ts +469 -0
- package/dist/tools/utility.js +1118 -0
- package/dist/tools/workspace.d.ts +25 -0
- package/dist/tools/workspace.js +61 -0
- package/package.json +66 -0
- package/scripts/build-chat-dmg.sh +210 -0
- package/scripts/build-chat-zip.sh +291 -0
- package/scripts/install-cep-windows.ps1 +99 -0
- package/scripts/install-cep.sh +66 -0
- package/scripts/install-chat-plugin.bat +67 -0
- package/scripts/install-chat-plugin.sh +85 -0
- package/scripts/install-windows.bat +95 -0
- package/scripts/package.mjs +218 -0
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
|
+
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
export function getEffectsTools(bridgeOptions) {
|
|
4
|
+
return {
|
|
5
|
+
apply_effect: {
|
|
6
|
+
description: `Apply a video effect to a clip by name. Uses QE DOM for effect lookup.
|
|
7
|
+
|
|
8
|
+
Preconditions: Active sequence required. The clip must exist on the timeline. Use list_available_effects to find exact effect names before calling this tool.
|
|
9
|
+
|
|
10
|
+
Common effect names: "Gaussian Blur", "Lumetri Color", "Warp Stabilizer", "Unsharp Mask", "Fast Color Corrector", "Brightness & Contrast", "Hue/Saturation", "Sharpen", "Video Limiter", "Timecode".
|
|
11
|
+
|
|
12
|
+
After applying, use get_effect_properties to see the effect's parameters, then set_effect_property or add_keyframe to adjust values.
|
|
13
|
+
|
|
14
|
+
Example: apply_effect({ node_id: "abc123", effect_name: "Gaussian Blur" })
|
|
15
|
+
Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
16
|
+
parameters: {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
node_id: {
|
|
20
|
+
type: "string",
|
|
21
|
+
description: "Node ID of the clip to apply the effect to",
|
|
22
|
+
},
|
|
23
|
+
effect_name: {
|
|
24
|
+
type: "string",
|
|
25
|
+
description: "Name of the effect (e.g., 'Gaussian Blur', 'Lumetri Color')",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
required: ["node_id", "effect_name"],
|
|
29
|
+
},
|
|
30
|
+
handler: async (args) => {
|
|
31
|
+
const script = buildToolScript(`
|
|
32
|
+
app.enableQE();
|
|
33
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
34
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
35
|
+
|
|
36
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
37
|
+
if (!result) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
|
|
38
|
+
|
|
39
|
+
// Find the effect in QE
|
|
40
|
+
var effectName = "${escapeForExtendScript(args.effect_name)}";
|
|
41
|
+
var qeTrack = result.trackType === "video"
|
|
42
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
43
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
44
|
+
|
|
45
|
+
if (!qeTrack) return __error("QE track not found");
|
|
46
|
+
|
|
47
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
48
|
+
if (!qeClip) return __error("QE clip not found");
|
|
49
|
+
|
|
50
|
+
// Search for the effect
|
|
51
|
+
var effects = qe.project.getVideoEffectList();
|
|
52
|
+
var found = false;
|
|
53
|
+
for (var i = 0; i < effects.numItems; i++) {
|
|
54
|
+
if (effects[i].name === effectName) {
|
|
55
|
+
qeClip.addVideoEffect(effects[i]);
|
|
56
|
+
found = true;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!found) return __error("Effect not found: " + effectName);
|
|
62
|
+
return __result({ applied: true, effect: effectName, clipName: result.clip.name });
|
|
63
|
+
`);
|
|
64
|
+
return sendCommand(script, bridgeOptions);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
apply_audio_effect: {
|
|
68
|
+
description: "Apply an audio effect to a clip",
|
|
69
|
+
parameters: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
node_id: {
|
|
73
|
+
type: "string",
|
|
74
|
+
description: "Node ID of the clip",
|
|
75
|
+
},
|
|
76
|
+
effect_name: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "Name of the audio effect",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ["node_id", "effect_name"],
|
|
82
|
+
},
|
|
83
|
+
handler: async (args) => {
|
|
84
|
+
const script = buildToolScript(`
|
|
85
|
+
app.enableQE();
|
|
86
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
87
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
88
|
+
|
|
89
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
90
|
+
if (!result) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
|
|
91
|
+
if (result.trackType !== "audio") return __error("node_id is not an audio clip");
|
|
92
|
+
|
|
93
|
+
var effectName = "${escapeForExtendScript(args.effect_name)}";
|
|
94
|
+
var qeTrack = qeSeq.getAudioTrackAt(result.trackIndex);
|
|
95
|
+
if (!qeTrack) return __error("QE audio track not found");
|
|
96
|
+
|
|
97
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
98
|
+
if (!qeClip) return __error("QE clip not found");
|
|
99
|
+
|
|
100
|
+
var effects = qe.project.getAudioEffectList();
|
|
101
|
+
var found = false;
|
|
102
|
+
for (var i = 0; i < effects.numItems; i++) {
|
|
103
|
+
if (effects[i].name === effectName) {
|
|
104
|
+
qeClip.addAudioEffect(effects[i]);
|
|
105
|
+
found = true;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!found) return __error("Audio effect not found: " + effectName);
|
|
111
|
+
return __result({ applied: true, effect: effectName });
|
|
112
|
+
`);
|
|
113
|
+
return sendCommand(script, bridgeOptions);
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
remove_effect: {
|
|
117
|
+
description: "Remove an effect from a clip by its index or name",
|
|
118
|
+
parameters: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {
|
|
121
|
+
node_id: {
|
|
122
|
+
type: "string",
|
|
123
|
+
description: "Node ID of the clip",
|
|
124
|
+
},
|
|
125
|
+
effect_index: {
|
|
126
|
+
type: "number",
|
|
127
|
+
description: "Index of the effect to remove (0-based). Use get_clip_properties to see effects list.",
|
|
128
|
+
},
|
|
129
|
+
effect_name: {
|
|
130
|
+
type: "string",
|
|
131
|
+
description: "Name of the effect to remove (alternative to effect_index)",
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
required: ["node_id"],
|
|
135
|
+
},
|
|
136
|
+
handler: async (args) => {
|
|
137
|
+
const script = buildToolScript(`
|
|
138
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
139
|
+
if (!result) return __error("Clip not found");
|
|
140
|
+
|
|
141
|
+
var clip = result.clip;
|
|
142
|
+
${args.effect_index !== undefined ? `
|
|
143
|
+
if (${args.effect_index} >= clip.components.numItems) return __error("Effect index out of range");
|
|
144
|
+
var effectName = clip.components[${args.effect_index}].displayName;
|
|
145
|
+
clip.components[${args.effect_index}].remove();
|
|
146
|
+
return __result({ removed: true, effect: effectName });
|
|
147
|
+
` : `
|
|
148
|
+
var effectName = "${escapeForExtendScript(args.effect_name || "")}";
|
|
149
|
+
var found = false;
|
|
150
|
+
for (var i = clip.components.numItems - 1; i >= 0; i--) {
|
|
151
|
+
if (clip.components[i].displayName === effectName) {
|
|
152
|
+
clip.components[i].remove();
|
|
153
|
+
found = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!found) return __error("Effect not found: " + effectName);
|
|
158
|
+
return __result({ removed: true, effect: effectName });
|
|
159
|
+
`}
|
|
160
|
+
`);
|
|
161
|
+
return sendCommand(script, bridgeOptions);
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
list_available_effects: {
|
|
165
|
+
description: "List all available video effects in Premiere Pro.",
|
|
166
|
+
parameters: {},
|
|
167
|
+
handler: async () => {
|
|
168
|
+
const effects = [
|
|
169
|
+
// Color & Grading
|
|
170
|
+
{ name: "Lumetri Color", category: "Color Correction" },
|
|
171
|
+
{ name: "Brightness & Contrast", category: "Color Correction" },
|
|
172
|
+
{ name: "Hue/Saturation", category: "Color Correction" },
|
|
173
|
+
{ name: "Fast Color Corrector", category: "Color Correction" },
|
|
174
|
+
{ name: "Three-Way Color Corrector", category: "Color Correction" },
|
|
175
|
+
{ name: "Color Balance", category: "Color Correction" },
|
|
176
|
+
{ name: "Change to Color", category: "Color Correction" },
|
|
177
|
+
{ name: "Video Limiter", category: "Color Correction" },
|
|
178
|
+
{ name: "Luma Curve", category: "Color Correction" },
|
|
179
|
+
{ name: "RGB Curves", category: "Color Correction" },
|
|
180
|
+
// Blur & Sharpen
|
|
181
|
+
{ name: "Gaussian Blur", category: "Blur & Sharpen" },
|
|
182
|
+
{ name: "Fast Blur", category: "Blur & Sharpen" },
|
|
183
|
+
{ name: "Directional Blur", category: "Blur & Sharpen" },
|
|
184
|
+
{ name: "Radial Blur", category: "Blur & Sharpen" },
|
|
185
|
+
{ name: "Sharpen", category: "Blur & Sharpen" },
|
|
186
|
+
{ name: "Unsharp Mask", category: "Blur & Sharpen" },
|
|
187
|
+
{ name: "Camera Blur", category: "Blur & Sharpen" },
|
|
188
|
+
// Distort
|
|
189
|
+
{ name: "Warp Stabilizer", category: "Distort" },
|
|
190
|
+
{ name: "Lens Distortion", category: "Distort" },
|
|
191
|
+
{ name: "Corner Pin", category: "Distort" },
|
|
192
|
+
{ name: "Spherize", category: "Distort" },
|
|
193
|
+
{ name: "Mirror", category: "Distort" },
|
|
194
|
+
{ name: "Transform", category: "Distort" },
|
|
195
|
+
{ name: "Magnify", category: "Distort" },
|
|
196
|
+
{ name: "Offset", category: "Distort" },
|
|
197
|
+
// Generate
|
|
198
|
+
{ name: "4-Color Gradient", category: "Generate" },
|
|
199
|
+
{ name: "Gradient", category: "Generate" },
|
|
200
|
+
{ name: "Cell Pattern", category: "Generate" },
|
|
201
|
+
{ name: "Checkerboard", category: "Generate" },
|
|
202
|
+
{ name: "Lens Flare", category: "Generate" },
|
|
203
|
+
{ name: "Lightning", category: "Generate" },
|
|
204
|
+
// Keying
|
|
205
|
+
{ name: "Ultra Key", category: "Keying" },
|
|
206
|
+
{ name: "Chroma Key", category: "Keying" },
|
|
207
|
+
{ name: "Color Key", category: "Keying" },
|
|
208
|
+
{ name: "Luma Key", category: "Keying" },
|
|
209
|
+
{ name: "Track Matte Key", category: "Keying" },
|
|
210
|
+
{ name: "Difference Matte", category: "Keying" },
|
|
211
|
+
// Noise & Grain
|
|
212
|
+
{ name: "Noise", category: "Noise & Grain" },
|
|
213
|
+
{ name: "Median", category: "Noise & Grain" },
|
|
214
|
+
{ name: "Dust & Scratches", category: "Noise & Grain" },
|
|
215
|
+
// Stylize
|
|
216
|
+
{ name: "Mosaic", category: "Stylize" },
|
|
217
|
+
{ name: "Posterize", category: "Stylize" },
|
|
218
|
+
{ name: "Threshold", category: "Stylize" },
|
|
219
|
+
{ name: "Find Edges", category: "Stylize" },
|
|
220
|
+
{ name: "Emboss", category: "Stylize" },
|
|
221
|
+
{ name: "Solarize", category: "Stylize" },
|
|
222
|
+
{ name: "Strobe Light", category: "Stylize" },
|
|
223
|
+
// Time
|
|
224
|
+
{ name: "Posterize Time", category: "Time" },
|
|
225
|
+
{ name: "Echo", category: "Time" },
|
|
226
|
+
// Transition effects
|
|
227
|
+
{ name: "Block Dissolve", category: "Transition" },
|
|
228
|
+
{ name: "Gradient Wipe", category: "Transition" },
|
|
229
|
+
{ name: "Linear Wipe", category: "Transition" },
|
|
230
|
+
// Utility
|
|
231
|
+
{ name: "Timecode", category: "Utility" },
|
|
232
|
+
{ name: "Clip Name", category: "Utility" },
|
|
233
|
+
{ name: "SDR Conform", category: "Utility" },
|
|
234
|
+
];
|
|
235
|
+
return { success: true, data: { effects, count: effects.length, note: "Static list of common Premiere Pro video effects. Use apply_effect with these exact names." } };
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
list_available_audio_effects: {
|
|
239
|
+
description: "List all available audio effects in Premiere Pro.",
|
|
240
|
+
parameters: {},
|
|
241
|
+
handler: async () => {
|
|
242
|
+
const effects = [
|
|
243
|
+
// Amplitude & Compression
|
|
244
|
+
{ name: "Dynamics Processing", category: "Amplitude & Compression" },
|
|
245
|
+
{ name: "Hard Limiter", category: "Amplitude & Compression" },
|
|
246
|
+
{ name: "Multiband Compressor", category: "Amplitude & Compression" },
|
|
247
|
+
{ name: "Single-band Compressor", category: "Amplitude & Compression" },
|
|
248
|
+
{ name: "Tube-modeled Compressor", category: "Amplitude & Compression" },
|
|
249
|
+
// Delay & Echo
|
|
250
|
+
{ name: "Analog Delay", category: "Delay & Echo" },
|
|
251
|
+
{ name: "Delay", category: "Delay & Echo" },
|
|
252
|
+
{ name: "Multitap Delay", category: "Delay & Echo" },
|
|
253
|
+
// Filter & EQ
|
|
254
|
+
{ name: "FFT Filter", category: "Filter & EQ" },
|
|
255
|
+
{ name: "Graphic Equalizer (10 Bands)", category: "Filter & EQ" },
|
|
256
|
+
{ name: "Graphic Equalizer (20 Bands)", category: "Filter & EQ" },
|
|
257
|
+
{ name: "Parametric Equalizer", category: "Filter & EQ" },
|
|
258
|
+
{ name: "Scientific Filter", category: "Filter & EQ" },
|
|
259
|
+
// Modulation
|
|
260
|
+
{ name: "Chorus/Flanger", category: "Modulation" },
|
|
261
|
+
{ name: "Flanger", category: "Modulation" },
|
|
262
|
+
{ name: "Phaser", category: "Modulation" },
|
|
263
|
+
// Noise Reduction / Restoration
|
|
264
|
+
{ name: "Adaptive Noise Reduction", category: "Noise Reduction" },
|
|
265
|
+
{ name: "Automatic Click Remover", category: "Noise Reduction" },
|
|
266
|
+
{ name: "DeNoise", category: "Noise Reduction" },
|
|
267
|
+
{ name: "DeHum", category: "Noise Reduction" },
|
|
268
|
+
{ name: "DeEsser", category: "Noise Reduction" },
|
|
269
|
+
// Reverb
|
|
270
|
+
{ name: "Convolution Reverb", category: "Reverb" },
|
|
271
|
+
{ name: "Full Reverb", category: "Reverb" },
|
|
272
|
+
{ name: "Reverb", category: "Reverb" },
|
|
273
|
+
// Special
|
|
274
|
+
{ name: "Pitch Shifter", category: "Special" },
|
|
275
|
+
{ name: "Vocal Enhancer", category: "Special" },
|
|
276
|
+
// Stereo Imagery
|
|
277
|
+
{ name: "Center Channel Extractor", category: "Stereo Imagery" },
|
|
278
|
+
{ name: "Stereo Expander", category: "Stereo Imagery" },
|
|
279
|
+
// Time & Pitch
|
|
280
|
+
{ name: "Pitch & Time", category: "Time & Pitch" },
|
|
281
|
+
];
|
|
282
|
+
return { success: true, data: { effects, count: effects.length, note: "Static list of common Premiere Pro audio effects. Use apply_audio_effect with these exact names." } };
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
color_correct: {
|
|
286
|
+
description: `Apply color correction to a clip using Lumetri Color. Automatically applies the Lumetri Color effect if not already present, then sets the specified parameters.
|
|
287
|
+
|
|
288
|
+
Preconditions: Active sequence required. Clip must exist on the timeline.
|
|
289
|
+
|
|
290
|
+
All parameters are optional — only the ones you provide will be changed. Values outside their valid range are clamped by Premiere Pro.
|
|
291
|
+
|
|
292
|
+
Parameter ranges:
|
|
293
|
+
- exposure: -5.0 to +5.0 (EV stops; 0 = no change)
|
|
294
|
+
- contrast: -100 to +100 (0 = no change)
|
|
295
|
+
- highlights: -100 to +100
|
|
296
|
+
- shadows: -100 to +100
|
|
297
|
+
- whites: -100 to +100
|
|
298
|
+
- blacks: -100 to +100
|
|
299
|
+
- temperature: -100 to +100 (negative = cooler/blue, positive = warmer/orange)
|
|
300
|
+
- tint: -100 to +100 (negative = green, positive = magenta)
|
|
301
|
+
- saturation: 0 to 200 (100 = no change, 0 = grayscale)
|
|
302
|
+
|
|
303
|
+
Example: color_correct({ node_id: "abc123", exposure: 0.5, contrast: 10, saturation: 110 })
|
|
304
|
+
Example: color_correct({ node_id: "abc123", temperature: -20, highlights: -30, shadows: 15 })`,
|
|
305
|
+
parameters: {
|
|
306
|
+
type: "object",
|
|
307
|
+
properties: {
|
|
308
|
+
node_id: {
|
|
309
|
+
type: "string",
|
|
310
|
+
description: "Node ID of the clip",
|
|
311
|
+
},
|
|
312
|
+
exposure: { type: "number", description: "Exposure adjustment (-4.0 to 4.0)" },
|
|
313
|
+
contrast: { type: "number", description: "Contrast adjustment (-100 to 100)" },
|
|
314
|
+
highlights: { type: "number", description: "Highlights adjustment (-100 to 100)" },
|
|
315
|
+
shadows: { type: "number", description: "Shadows adjustment (-100 to 100)" },
|
|
316
|
+
whites: { type: "number", description: "Whites adjustment (-100 to 100)" },
|
|
317
|
+
blacks: { type: "number", description: "Blacks adjustment (-100 to 100)" },
|
|
318
|
+
temperature: { type: "number", description: "Color temperature adjustment" },
|
|
319
|
+
tint: { type: "number", description: "Tint adjustment" },
|
|
320
|
+
saturation: { type: "number", description: "Saturation (0-200, 100 = normal)" },
|
|
321
|
+
},
|
|
322
|
+
required: ["node_id"],
|
|
323
|
+
},
|
|
324
|
+
handler: async (args) => {
|
|
325
|
+
// First apply Lumetri Color effect, then set its properties
|
|
326
|
+
const script = buildToolScript(`
|
|
327
|
+
app.enableQE();
|
|
328
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
329
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
330
|
+
|
|
331
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
332
|
+
if (!result) return __error("Clip not found");
|
|
333
|
+
|
|
334
|
+
// Apply Lumetri Color if not already present
|
|
335
|
+
var clip = result.clip;
|
|
336
|
+
var lumetri = __findIntrinsic(clip, "lumetri");
|
|
337
|
+
|
|
338
|
+
if (!lumetri) {
|
|
339
|
+
var qeTrack = qeSeq.getVideoTrackAt(result.trackIndex);
|
|
340
|
+
if (!qeTrack) return __error("QE video track not found");
|
|
341
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
342
|
+
if (!qeClip) return __error("QE clip not found");
|
|
343
|
+
var effects = qe.project.getVideoEffectList();
|
|
344
|
+
// qe.project.getVideoEffectList() returns LOCALIZED displayNames in
|
|
345
|
+
// non-English Premiere installs (e.g. "Color Lumetri" in es-ES).
|
|
346
|
+
// Match against a list of candidate names across locales.
|
|
347
|
+
var lumetriNames = ["Lumetri Color", "Color Lumetri", "Lumetri-Farbe", "Couleur Lumetri", "Lumetri カラー", "色彩Lumetri"];
|
|
348
|
+
var lumetriEffect = null;
|
|
349
|
+
for (var i = 0; i < effects.numItems; i++) {
|
|
350
|
+
for (var n = 0; n < lumetriNames.length; n++) {
|
|
351
|
+
if (effects[i].name === lumetriNames[n]) {
|
|
352
|
+
lumetriEffect = effects[i];
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (lumetriEffect) break;
|
|
357
|
+
}
|
|
358
|
+
// Fallback: any effect whose name contains "Lumetri"
|
|
359
|
+
if (!lumetriEffect) {
|
|
360
|
+
for (var j = 0; j < effects.numItems; j++) {
|
|
361
|
+
if (effects[j].name && effects[j].name.indexOf("Lumetri") !== -1) {
|
|
362
|
+
lumetriEffect = effects[j];
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (!lumetriEffect) return __error("Lumetri Color effect not found in available video effects");
|
|
368
|
+
qeClip.addVideoEffect(lumetriEffect);
|
|
369
|
+
// Re-find the component after applying
|
|
370
|
+
lumetri = __findIntrinsic(clip, "lumetri");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (!lumetri) return __error("Could not apply or find Lumetri Color effect");
|
|
374
|
+
|
|
375
|
+
// Set Lumetri properties. Params are nested in sub-groups; __findProp
|
|
376
|
+
// descends one level to locate them. Each setValue is guarded.
|
|
377
|
+
var changes = {};
|
|
378
|
+
var failed = {};
|
|
379
|
+
|
|
380
|
+
function __setLumetri(displayNames, value, key) {
|
|
381
|
+
var prop = __findProp(lumetri, displayNames);
|
|
382
|
+
if (!prop) { failed[key] = "property not found"; return; }
|
|
383
|
+
try {
|
|
384
|
+
prop.setValue(value, true);
|
|
385
|
+
changes[key] = value;
|
|
386
|
+
} catch (e) {
|
|
387
|
+
failed[key] = e.toString();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
${args.exposure !== undefined ? `__setLumetri(["Exposure", "Exposición", "Belichtung", "Exposition"], ${args.exposure}, "exposure");` : ""}
|
|
392
|
+
${args.contrast !== undefined ? `__setLumetri(["Contrast", "Contraste", "Kontrast", "Contraste"], ${args.contrast}, "contrast");` : ""}
|
|
393
|
+
${args.highlights !== undefined ? `__setLumetri(["Highlights", "Iluminaciones", "Lichter", "Hautes lumières"], ${args.highlights}, "highlights");` : ""}
|
|
394
|
+
${args.shadows !== undefined ? `__setLumetri(["Shadows", "Sombras", "Schatten", "Ombres"], ${args.shadows}, "shadows");` : ""}
|
|
395
|
+
${args.whites !== undefined ? `__setLumetri(["Whites", "Blancos", "Weißwerte", "Blancs"], ${args.whites}, "whites");` : ""}
|
|
396
|
+
${args.blacks !== undefined ? `__setLumetri(["Blacks", "Negros", "Schwarzwerte", "Noirs"], ${args.blacks}, "blacks");` : ""}
|
|
397
|
+
${args.temperature !== undefined ? `__setLumetri(["Temperature", "Temperatura", "Temperatur", "Température"], ${args.temperature}, "temperature");` : ""}
|
|
398
|
+
${args.tint !== undefined ? `__setLumetri(["Tint", "Matiz", "Farbton", "Teinte"], ${args.tint}, "tint");` : ""}
|
|
399
|
+
${args.saturation !== undefined ? `__setLumetri(["Saturation", "Saturación", "Sättigung", "Saturation"], ${args.saturation}, "saturation");` : ""}
|
|
400
|
+
|
|
401
|
+
return __result({ colorCorrected: true, clipName: clip.name, changes: changes, failed: failed });
|
|
402
|
+
`);
|
|
403
|
+
return sendCommand(script, bridgeOptions);
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
apply_lut: {
|
|
407
|
+
description: `Apply a LUT (Look-Up Table) file to a clip via Lumetri Color's Creative or Input LUT slot.
|
|
408
|
+
|
|
409
|
+
Preconditions: Active sequence required. The LUT file must be accessible on disk at the specified path. Lumetri Color effect is automatically applied to the clip if not already present.
|
|
410
|
+
|
|
411
|
+
Supported LUT formats: .cube, .look, .lut, .3dl, .mga.
|
|
412
|
+
|
|
413
|
+
Parameters:
|
|
414
|
+
- node_id: Clip to apply the LUT to.
|
|
415
|
+
- lut_path: Absolute path to the LUT file (e.g., "C:\\LUTs\\rec709.cube" or "/Users/you/LUTs/film.cube").
|
|
416
|
+
- lut_strength: Intensity of the LUT effect (0.0 = no effect, 1.0 = full strength, default: 1.0).
|
|
417
|
+
|
|
418
|
+
Example: apply_lut({ node_id: "abc123", lut_path: "/Users/you/LUTs/orange-teal.cube", lut_strength: 0.8 })`,
|
|
419
|
+
parameters: {
|
|
420
|
+
type: "object",
|
|
421
|
+
properties: {
|
|
422
|
+
node_id: {
|
|
423
|
+
type: "string",
|
|
424
|
+
description: "Node ID of the clip",
|
|
425
|
+
},
|
|
426
|
+
lut_path: {
|
|
427
|
+
type: "string",
|
|
428
|
+
description: "Full path to the .cube or .3dl LUT file",
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
required: ["node_id", "lut_path"],
|
|
432
|
+
},
|
|
433
|
+
handler: async (args) => {
|
|
434
|
+
const script = buildToolScript(`
|
|
435
|
+
app.enableQE();
|
|
436
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
437
|
+
if (!result) return __error("Clip not found");
|
|
438
|
+
|
|
439
|
+
var clip = result.clip;
|
|
440
|
+
|
|
441
|
+
// Find or apply Lumetri Color
|
|
442
|
+
var lumetriComp = __findIntrinsic(clip, "lumetri");
|
|
443
|
+
|
|
444
|
+
if (!lumetriComp) {
|
|
445
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
446
|
+
var qeTrack = qeSeq.getVideoTrackAt(result.trackIndex);
|
|
447
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
448
|
+
var effects = qe.project.getVideoEffectList();
|
|
449
|
+
for (var i = 0; i < effects.numItems; i++) {
|
|
450
|
+
if (effects[i].name === "Lumetri Color") {
|
|
451
|
+
qeClip.addVideoEffect(effects[i]);
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
// Re-find the component
|
|
456
|
+
lumetriComp = __findIntrinsic(clip, "lumetri");
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (!lumetriComp) return __error("Could not apply Lumetri Color effect");
|
|
460
|
+
|
|
461
|
+
// Set the LUT path (Input LUT is nested within Lumetri groups)
|
|
462
|
+
var lutProp = __findProp(lumetriComp, ["Input LUT", "Creative Look", "LUT de entrada"]);
|
|
463
|
+
if (!lutProp) return __error("Input LUT property not found on Lumetri Color");
|
|
464
|
+
lutProp.setValue("${escapeForExtendScript(args.lut_path)}", true);
|
|
465
|
+
|
|
466
|
+
return __result({ lutApplied: true, clipName: clip.name, lutPath: "${escapeForExtendScript(args.lut_path)}" });
|
|
467
|
+
`);
|
|
468
|
+
return sendCommand(script, bridgeOptions);
|
|
469
|
+
},
|
|
470
|
+
},
|
|
471
|
+
stabilize_clip: {
|
|
472
|
+
description: "Apply the Warp Stabilizer effect to a clip for video stabilization. Uses QE DOM.",
|
|
473
|
+
parameters: {
|
|
474
|
+
type: "object",
|
|
475
|
+
properties: {
|
|
476
|
+
node_id: {
|
|
477
|
+
type: "string",
|
|
478
|
+
description: "Node ID of the clip to stabilize",
|
|
479
|
+
},
|
|
480
|
+
smoothness: {
|
|
481
|
+
type: "number",
|
|
482
|
+
description: "Stabilization smoothness percentage (default: 50). Higher = smoother but more cropping.",
|
|
483
|
+
},
|
|
484
|
+
method: {
|
|
485
|
+
type: "string",
|
|
486
|
+
enum: ["Subspace Warp", "Position", "Position, Scale, Rotation"],
|
|
487
|
+
description: "Stabilization method (default: 'Subspace Warp')",
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
required: ["node_id"],
|
|
491
|
+
},
|
|
492
|
+
handler: async (args) => {
|
|
493
|
+
const script = buildToolScript(`
|
|
494
|
+
app.enableQE();
|
|
495
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
496
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
497
|
+
|
|
498
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
499
|
+
if (!result) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
|
|
500
|
+
|
|
501
|
+
var qeTrack = result.trackType === "video"
|
|
502
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
503
|
+
: null;
|
|
504
|
+
if (!qeTrack) return __error("Warp Stabilizer can only be applied to video clips");
|
|
505
|
+
|
|
506
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
507
|
+
if (!qeClip) return __error("QE clip not found");
|
|
508
|
+
|
|
509
|
+
// Find and apply Warp Stabilizer
|
|
510
|
+
var effects = qe.project.getVideoEffectList();
|
|
511
|
+
var found = false;
|
|
512
|
+
for (var i = 0; i < effects.numItems; i++) {
|
|
513
|
+
if (effects[i].name === "Warp Stabilizer") {
|
|
514
|
+
qeClip.addVideoEffect(effects[i]);
|
|
515
|
+
found = true;
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (!found) return __error("Warp Stabilizer effect not found");
|
|
521
|
+
|
|
522
|
+
// Set properties if specified
|
|
523
|
+
var clip = result.clip;
|
|
524
|
+
var changes = { stabilized: true };
|
|
525
|
+
${args.smoothness !== undefined || args.method !== undefined ? `
|
|
526
|
+
for (var i = 0; i < clip.components.numItems; i++) {
|
|
527
|
+
var comp = clip.components[i];
|
|
528
|
+
if (comp.displayName === "Warp Stabilizer") {
|
|
529
|
+
for (var p = 0; p < comp.properties.numItems; p++) {
|
|
530
|
+
var prop = comp.properties[p];
|
|
531
|
+
${args.smoothness !== undefined ? `
|
|
532
|
+
if (prop.displayName === "Smoothness") {
|
|
533
|
+
prop.setValue(${args.smoothness}, true);
|
|
534
|
+
changes.smoothness = ${args.smoothness};
|
|
535
|
+
}` : ""}
|
|
536
|
+
${args.method !== undefined ? `
|
|
537
|
+
if (prop.displayName === "Method") {
|
|
538
|
+
prop.setValue("${escapeForExtendScript(args.method)}", true);
|
|
539
|
+
changes.method = "${escapeForExtendScript(args.method)}";
|
|
540
|
+
}` : ""}
|
|
541
|
+
}
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
` : ""}
|
|
546
|
+
|
|
547
|
+
return __result({ clipName: clip.name, info: "Warp Stabilizer applied. Analysis will begin automatically.", changes: changes });
|
|
548
|
+
`);
|
|
549
|
+
return sendCommand(script, bridgeOptions);
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
//# sourceMappingURL=effects.js.map
|