@synthetic-ai/premiere-mcp 2.1.0 → 2.3.0-dev.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 +135 -123
- package/LICENSE +21 -21
- package/README.md +242 -242
- package/cep-plugin/.debug +8 -8
- package/cep-plugin/CSInterface.js +92 -92
- package/cep-plugin/host.jsx +7 -7
- package/cep-plugin/index.html +472 -472
- package/cep-plugin/main.js +6 -0
- package/cep-plugin/premiere.jsx +24947 -24947
- package/dist/bridge/script-builder.js +378 -378
- package/dist/index.js +103 -4
- package/dist/license.js +38 -0
- package/dist/server.js +60 -60
- package/dist/tools/advanced.js +357 -357
- package/dist/tools/audio-advanced.js +1049 -1049
- package/dist/tools/audio.js +42 -42
- package/dist/tools/captions.js +27 -27
- package/dist/tools/clipboard.js +214 -214
- package/dist/tools/color-advanced.js +253 -253
- package/dist/tools/discovery.js +291 -291
- package/dist/tools/effects.js +285 -285
- package/dist/tools/export-presets.js +206 -206
- package/dist/tools/export.js +255 -255
- package/dist/tools/health.js +10 -10
- package/dist/tools/inspection.js +885 -885
- package/dist/tools/keyframes.js +369 -369
- package/dist/tools/markers.js +89 -89
- package/dist/tools/media.js +178 -178
- package/dist/tools/metadata.js +94 -94
- package/dist/tools/multicam.js +50 -50
- package/dist/tools/playback.js +15 -15
- package/dist/tools/playhead.js +95 -95
- package/dist/tools/project-manager.js +21 -21
- package/dist/tools/project.js +149 -149
- package/dist/tools/scripting.js +319 -319
- package/dist/tools/selection.js +202 -202
- package/dist/tools/sequence-advanced.js +379 -379
- package/dist/tools/sequence-settings.js +564 -564
- package/dist/tools/sequence.js +167 -167
- package/dist/tools/source-monitor.js +68 -68
- package/dist/tools/text.js +58 -58
- package/dist/tools/timeline.js +312 -312
- package/dist/tools/track-management.js +446 -446
- package/dist/tools/track-targeting.js +635 -635
- package/dist/tools/tracks.js +87 -87
- package/dist/tools/transitions-motion.js +174 -174
- package/dist/tools/transitions.js +111 -111
- package/dist/tools/utility.js +606 -606
- package/dist/tools/workspace.js +29 -29
- package/package.json +66 -66
- package/scripts/build-chat-dmg.sh +210 -210
- package/scripts/build-chat-zip.sh +291 -291
- package/scripts/install-cep-windows.ps1 +99 -99
- package/scripts/install-cep.sh +66 -66
- package/scripts/install-chat-plugin.bat +67 -67
- package/scripts/install-chat-plugin.sh +85 -85
- package/scripts/install-windows.bat +95 -95
- package/scripts/package.mjs +254 -254
package/dist/tools/effects.js
CHANGED
|
@@ -3,15 +3,15 @@ import { sendCommand } from "../bridge/file-bridge.js";
|
|
|
3
3
|
export function getEffectsTools(bridgeOptions) {
|
|
4
4
|
return {
|
|
5
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" })
|
|
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
15
|
Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
16
16
|
parameters: {
|
|
17
17
|
type: "object",
|
|
@@ -28,38 +28,38 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
28
28
|
required: ["node_id", "effect_name"],
|
|
29
29
|
},
|
|
30
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 });
|
|
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
63
|
`);
|
|
64
64
|
return sendCommand(script, bridgeOptions);
|
|
65
65
|
},
|
|
@@ -81,34 +81,34 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
81
81
|
required: ["node_id", "effect_name"],
|
|
82
82
|
},
|
|
83
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 });
|
|
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
112
|
`);
|
|
113
113
|
return sendCommand(script, bridgeOptions);
|
|
114
114
|
},
|
|
@@ -134,29 +134,29 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
134
134
|
required: ["node_id"],
|
|
135
135
|
},
|
|
136
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
|
-
`}
|
|
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
160
|
`);
|
|
161
161
|
return sendCommand(script, bridgeOptions);
|
|
162
162
|
},
|
|
@@ -283,24 +283,24 @@ Example: apply_effect({ node_id: "abc123", effect_name: "Lumetri Color" })`,
|
|
|
283
283
|
},
|
|
284
284
|
},
|
|
285
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 })
|
|
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
304
|
Example: color_correct({ node_id: "abc123", temperature: -20, highlights: -30, shadows: 15 })`,
|
|
305
305
|
parameters: {
|
|
306
306
|
type: "object",
|
|
@@ -323,98 +323,98 @@ Example: color_correct({ node_id: "abc123", temperature: -20, highlights: -30, s
|
|
|
323
323
|
},
|
|
324
324
|
handler: async (args) => {
|
|
325
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 });
|
|
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
402
|
`);
|
|
403
403
|
return sendCommand(script, bridgeOptions);
|
|
404
404
|
},
|
|
405
405
|
},
|
|
406
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
|
-
|
|
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
418
|
Example: apply_lut({ node_id: "abc123", lut_path: "/Users/you/LUTs/orange-teal.cube", lut_strength: 0.8 })`,
|
|
419
419
|
parameters: {
|
|
420
420
|
type: "object",
|
|
@@ -431,39 +431,39 @@ Example: apply_lut({ node_id: "abc123", lut_path: "/Users/you/LUTs/orange-teal.c
|
|
|
431
431
|
required: ["node_id", "lut_path"],
|
|
432
432
|
},
|
|
433
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)}" });
|
|
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
467
|
`);
|
|
468
468
|
return sendCommand(script, bridgeOptions);
|
|
469
469
|
},
|
|
@@ -490,61 +490,61 @@ Example: apply_lut({ node_id: "abc123", lut_path: "/Users/you/LUTs/orange-teal.c
|
|
|
490
490
|
required: ["node_id"],
|
|
491
491
|
},
|
|
492
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 });
|
|
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
548
|
`);
|
|
549
549
|
return sendCommand(script, bridgeOptions);
|
|
550
550
|
},
|