@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,923 @@
|
|
|
1
|
+
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
|
+
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
export function getAdvancedTools(bridgeOptions) {
|
|
4
|
+
return {
|
|
5
|
+
ripple_delete: {
|
|
6
|
+
description: "Ripple delete a clip (removes clip and closes the gap). Uses QE DOM.",
|
|
7
|
+
parameters: {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
node_id: {
|
|
11
|
+
type: "string",
|
|
12
|
+
description: "Node ID of the clip to ripple delete",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
required: ["node_id"],
|
|
16
|
+
},
|
|
17
|
+
handler: async (args) => {
|
|
18
|
+
const script = buildToolScript(`
|
|
19
|
+
app.enableQE();
|
|
20
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
21
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
22
|
+
|
|
23
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
24
|
+
if (!result) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
|
|
25
|
+
|
|
26
|
+
var qeTrack = result.trackType === "video"
|
|
27
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
28
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
29
|
+
if (!qeTrack) return __error("QE track not found");
|
|
30
|
+
|
|
31
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
32
|
+
if (!qeClip) return __error("QE clip not found");
|
|
33
|
+
|
|
34
|
+
qeClip.rippleDelete();
|
|
35
|
+
return __result({ rippleDeleted: true, clipName: result.clip.name });
|
|
36
|
+
`);
|
|
37
|
+
return sendCommand(script, bridgeOptions);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
roll_edit: {
|
|
41
|
+
description: "Perform a roll edit on a clip (adjusts the edit point between two adjacent clips). Uses QE DOM.",
|
|
42
|
+
parameters: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
node_id: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "Node ID of the clip",
|
|
48
|
+
},
|
|
49
|
+
offset_seconds: {
|
|
50
|
+
type: "number",
|
|
51
|
+
description: "Offset in seconds (positive = roll right, negative = roll left)",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: ["node_id", "offset_seconds"],
|
|
55
|
+
},
|
|
56
|
+
handler: async (args) => {
|
|
57
|
+
const script = buildToolScript(`
|
|
58
|
+
app.enableQE();
|
|
59
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
60
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
61
|
+
|
|
62
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
63
|
+
if (!result) return __error("Clip not found");
|
|
64
|
+
|
|
65
|
+
var qeTrack = result.trackType === "video"
|
|
66
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
67
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
68
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
69
|
+
if (!qeClip) return __error("QE clip not found");
|
|
70
|
+
|
|
71
|
+
var offsetTicks = __secondsToTicks(${args.offset_seconds}).toString();
|
|
72
|
+
qeClip.roll(offsetTicks);
|
|
73
|
+
return __result({ rolled: true, clipName: result.clip.name, offsetSeconds: ${args.offset_seconds} });
|
|
74
|
+
`);
|
|
75
|
+
return sendCommand(script, bridgeOptions);
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
slide_edit: {
|
|
79
|
+
description: "Perform a slide edit on a clip (moves clip without changing its duration, adjusting adjacent clips). Uses QE DOM.",
|
|
80
|
+
parameters: {
|
|
81
|
+
type: "object",
|
|
82
|
+
properties: {
|
|
83
|
+
node_id: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: "Node ID of the clip",
|
|
86
|
+
},
|
|
87
|
+
offset_seconds: {
|
|
88
|
+
type: "number",
|
|
89
|
+
description: "Offset in seconds (positive = slide right, negative = slide left)",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
required: ["node_id", "offset_seconds"],
|
|
93
|
+
},
|
|
94
|
+
handler: async (args) => {
|
|
95
|
+
const script = buildToolScript(`
|
|
96
|
+
app.enableQE();
|
|
97
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
98
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
99
|
+
|
|
100
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
101
|
+
if (!result) return __error("Clip not found");
|
|
102
|
+
|
|
103
|
+
var qeTrack = result.trackType === "video"
|
|
104
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
105
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
106
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
107
|
+
if (!qeClip) return __error("QE clip not found");
|
|
108
|
+
|
|
109
|
+
var offsetTicks = __secondsToTicks(${args.offset_seconds}).toString();
|
|
110
|
+
qeClip.slide(offsetTicks);
|
|
111
|
+
return __result({ slid: true, clipName: result.clip.name, offsetSeconds: ${args.offset_seconds} });
|
|
112
|
+
`);
|
|
113
|
+
return sendCommand(script, bridgeOptions);
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
slip_edit: {
|
|
117
|
+
description: "Perform a slip edit on a clip (changes source in/out points without moving clip on timeline). Uses QE DOM.",
|
|
118
|
+
parameters: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {
|
|
121
|
+
node_id: {
|
|
122
|
+
type: "string",
|
|
123
|
+
description: "Node ID of the clip",
|
|
124
|
+
},
|
|
125
|
+
offset_seconds: {
|
|
126
|
+
type: "number",
|
|
127
|
+
description: "Offset in seconds (positive = slip forward in source, negative = slip backward)",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
required: ["node_id", "offset_seconds"],
|
|
131
|
+
},
|
|
132
|
+
handler: async (args) => {
|
|
133
|
+
const script = buildToolScript(`
|
|
134
|
+
app.enableQE();
|
|
135
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
136
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
137
|
+
|
|
138
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
139
|
+
if (!result) return __error("Clip not found");
|
|
140
|
+
|
|
141
|
+
var qeTrack = result.trackType === "video"
|
|
142
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
143
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
144
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
145
|
+
if (!qeClip) return __error("QE clip not found");
|
|
146
|
+
|
|
147
|
+
var offsetTicks = __secondsToTicks(${args.offset_seconds}).toString();
|
|
148
|
+
qeClip.slip(offsetTicks);
|
|
149
|
+
return __result({ slipped: true, clipName: result.clip.name, offsetSeconds: ${args.offset_seconds} });
|
|
150
|
+
`);
|
|
151
|
+
return sendCommand(script, bridgeOptions);
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
move_clip_to_track: {
|
|
155
|
+
description: "Move a clip to a different track. Uses QE DOM.",
|
|
156
|
+
parameters: {
|
|
157
|
+
type: "object",
|
|
158
|
+
properties: {
|
|
159
|
+
node_id: {
|
|
160
|
+
type: "string",
|
|
161
|
+
description: "Node ID of the clip",
|
|
162
|
+
},
|
|
163
|
+
target_track_index: {
|
|
164
|
+
type: "number",
|
|
165
|
+
description: "Target track index (0-based)",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ["node_id", "target_track_index"],
|
|
169
|
+
},
|
|
170
|
+
handler: async (args) => {
|
|
171
|
+
const script = buildToolScript(`
|
|
172
|
+
app.enableQE();
|
|
173
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
174
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
175
|
+
|
|
176
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
177
|
+
if (!result) return __error("Clip not found");
|
|
178
|
+
|
|
179
|
+
var qeTrack = result.trackType === "video"
|
|
180
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
181
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
182
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
183
|
+
if (!qeClip) return __error("QE clip not found");
|
|
184
|
+
|
|
185
|
+
qeClip.moveToTrack(${args.target_track_index});
|
|
186
|
+
return __result({ moved: true, clipName: result.clip.name, newTrackIndex: ${args.target_track_index} });
|
|
187
|
+
`);
|
|
188
|
+
return sendCommand(script, bridgeOptions);
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
remove_all_effects: {
|
|
192
|
+
description: "Remove ALL effects from a clip. Uses QE DOM.",
|
|
193
|
+
parameters: {
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: {
|
|
196
|
+
node_id: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "Node ID of the clip",
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
required: ["node_id"],
|
|
202
|
+
},
|
|
203
|
+
handler: async (args) => {
|
|
204
|
+
const script = buildToolScript(`
|
|
205
|
+
app.enableQE();
|
|
206
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
207
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
208
|
+
|
|
209
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
210
|
+
if (!result) return __error("Clip not found");
|
|
211
|
+
|
|
212
|
+
var qeTrack = result.trackType === "video"
|
|
213
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
214
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
215
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
216
|
+
if (!qeClip) return __error("QE clip not found");
|
|
217
|
+
|
|
218
|
+
qeClip.removeEffects();
|
|
219
|
+
return __result({ removed: true, clipName: result.clip.name });
|
|
220
|
+
`);
|
|
221
|
+
return sendCommand(script, bridgeOptions);
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
set_clip_speed_qe: {
|
|
225
|
+
description: "Set clip playback speed using QE DOM (more reliable than ExtendScript). Supports reverse.",
|
|
226
|
+
parameters: {
|
|
227
|
+
type: "object",
|
|
228
|
+
properties: {
|
|
229
|
+
node_id: {
|
|
230
|
+
type: "string",
|
|
231
|
+
description: "Node ID of the clip",
|
|
232
|
+
},
|
|
233
|
+
speed_percent: {
|
|
234
|
+
type: "number",
|
|
235
|
+
description: "Speed as percentage (100 = normal, 200 = 2x, 50 = half speed)",
|
|
236
|
+
},
|
|
237
|
+
reverse: {
|
|
238
|
+
type: "boolean",
|
|
239
|
+
description: "Reverse playback direction (default: false)",
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
required: ["node_id", "speed_percent"],
|
|
243
|
+
},
|
|
244
|
+
handler: async (args) => {
|
|
245
|
+
const script = buildToolScript(`
|
|
246
|
+
app.enableQE();
|
|
247
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
248
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
249
|
+
|
|
250
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
251
|
+
if (!result) return __error("Clip not found");
|
|
252
|
+
|
|
253
|
+
var qeTrack = result.trackType === "video"
|
|
254
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
255
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
256
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
257
|
+
if (!qeClip) return __error("QE clip not found");
|
|
258
|
+
|
|
259
|
+
qeClip.setSpeed(${args.speed_percent});
|
|
260
|
+
${args.reverse ? `qeClip.setReverse(true);` : ""}
|
|
261
|
+
|
|
262
|
+
return __result({
|
|
263
|
+
speedSet: true,
|
|
264
|
+
clipName: result.clip.name,
|
|
265
|
+
speed: ${args.speed_percent},
|
|
266
|
+
reverse: ${!!args.reverse}
|
|
267
|
+
});
|
|
268
|
+
`);
|
|
269
|
+
return sendCommand(script, bridgeOptions);
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
reverse_clip: {
|
|
273
|
+
description: "Reverse a clip's playback direction. Uses QE DOM.",
|
|
274
|
+
parameters: {
|
|
275
|
+
type: "object",
|
|
276
|
+
properties: {
|
|
277
|
+
node_id: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "Node ID of the clip",
|
|
280
|
+
},
|
|
281
|
+
reverse: {
|
|
282
|
+
type: "boolean",
|
|
283
|
+
description: "True to reverse, false for normal (default: true)",
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
required: ["node_id"],
|
|
287
|
+
},
|
|
288
|
+
handler: async (args) => {
|
|
289
|
+
const rev = args.reverse !== false;
|
|
290
|
+
const script = buildToolScript(`
|
|
291
|
+
app.enableQE();
|
|
292
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
293
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
294
|
+
|
|
295
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
296
|
+
if (!result) return __error("Clip not found");
|
|
297
|
+
|
|
298
|
+
var qeTrack = result.trackType === "video"
|
|
299
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
300
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
301
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
302
|
+
if (!qeClip) return __error("QE clip not found");
|
|
303
|
+
|
|
304
|
+
qeClip.setReverse(${rev});
|
|
305
|
+
return __result({ reversed: ${rev}, clipName: result.clip.name });
|
|
306
|
+
`);
|
|
307
|
+
return sendCommand(script, bridgeOptions);
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
set_frame_blend: {
|
|
311
|
+
description: "Enable or disable frame blending on a clip. Uses QE DOM.",
|
|
312
|
+
parameters: {
|
|
313
|
+
type: "object",
|
|
314
|
+
properties: {
|
|
315
|
+
node_id: {
|
|
316
|
+
type: "string",
|
|
317
|
+
description: "Node ID of the clip",
|
|
318
|
+
},
|
|
319
|
+
enabled: {
|
|
320
|
+
type: "boolean",
|
|
321
|
+
description: "True to enable frame blending, false to disable",
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
required: ["node_id", "enabled"],
|
|
325
|
+
},
|
|
326
|
+
handler: async (args) => {
|
|
327
|
+
const script = buildToolScript(`
|
|
328
|
+
app.enableQE();
|
|
329
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
330
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
331
|
+
|
|
332
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
333
|
+
if (!result) return __error("Clip not found");
|
|
334
|
+
|
|
335
|
+
var qeTrack = result.trackType === "video"
|
|
336
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
337
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
338
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
339
|
+
if (!qeClip) return __error("QE clip not found");
|
|
340
|
+
|
|
341
|
+
qeClip.setFrameBlend(${args.enabled});
|
|
342
|
+
return __result({ frameBlend: ${args.enabled}, clipName: result.clip.name });
|
|
343
|
+
`);
|
|
344
|
+
return sendCommand(script, bridgeOptions);
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
set_time_interpolation: {
|
|
348
|
+
description: "Set time interpolation type for a clip (Frame Sampling, Frame Blending, Optical Flow). Uses QE DOM.",
|
|
349
|
+
parameters: {
|
|
350
|
+
type: "object",
|
|
351
|
+
properties: {
|
|
352
|
+
node_id: {
|
|
353
|
+
type: "string",
|
|
354
|
+
description: "Node ID of the clip",
|
|
355
|
+
},
|
|
356
|
+
interpolation_type: {
|
|
357
|
+
type: "number",
|
|
358
|
+
description: "0 = Frame Sampling, 1 = Frame Blending, 2 = Optical Flow",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
required: ["node_id", "interpolation_type"],
|
|
362
|
+
},
|
|
363
|
+
handler: async (args) => {
|
|
364
|
+
const script = buildToolScript(`
|
|
365
|
+
app.enableQE();
|
|
366
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
367
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
368
|
+
|
|
369
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
370
|
+
if (!result) return __error("Clip not found");
|
|
371
|
+
|
|
372
|
+
var qeTrack = result.trackType === "video"
|
|
373
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
374
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
375
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
376
|
+
if (!qeClip) return __error("QE clip not found");
|
|
377
|
+
|
|
378
|
+
qeClip.setTimeInterpolationType(${args.interpolation_type});
|
|
379
|
+
var typeNames = ["Frame Sampling", "Frame Blending", "Optical Flow"];
|
|
380
|
+
return __result({
|
|
381
|
+
set: true,
|
|
382
|
+
clipName: result.clip.name,
|
|
383
|
+
interpolationType: typeNames[${args.interpolation_type}] || "Unknown"
|
|
384
|
+
});
|
|
385
|
+
`);
|
|
386
|
+
return sendCommand(script, bridgeOptions);
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
rename_clip: {
|
|
390
|
+
description: "Rename a clip on the timeline. Uses QE DOM.",
|
|
391
|
+
parameters: {
|
|
392
|
+
type: "object",
|
|
393
|
+
properties: {
|
|
394
|
+
node_id: {
|
|
395
|
+
type: "string",
|
|
396
|
+
description: "Node ID of the clip",
|
|
397
|
+
},
|
|
398
|
+
new_name: {
|
|
399
|
+
type: "string",
|
|
400
|
+
description: "New name for the clip",
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
required: ["node_id", "new_name"],
|
|
404
|
+
},
|
|
405
|
+
handler: async (args) => {
|
|
406
|
+
const script = buildToolScript(`
|
|
407
|
+
app.enableQE();
|
|
408
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
409
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
410
|
+
|
|
411
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
412
|
+
if (!result) return __error("Clip not found");
|
|
413
|
+
|
|
414
|
+
var qeTrack = result.trackType === "video"
|
|
415
|
+
? qeSeq.getVideoTrackAt(result.trackIndex)
|
|
416
|
+
: qeSeq.getAudioTrackAt(result.trackIndex);
|
|
417
|
+
var qeClip = qeTrack.getItemAt(result.clipIndex);
|
|
418
|
+
if (!qeClip) return __error("QE clip not found");
|
|
419
|
+
|
|
420
|
+
var oldName = result.clip.name;
|
|
421
|
+
qeClip.setName("${escapeForExtendScript(args.new_name)}");
|
|
422
|
+
return __result({ renamed: true, oldName: oldName, newName: "${escapeForExtendScript(args.new_name)}" });
|
|
423
|
+
`);
|
|
424
|
+
return sendCommand(script, bridgeOptions);
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
get_clip_speed: {
|
|
428
|
+
description: "Get the playback speed and reverse state of a clip",
|
|
429
|
+
parameters: {
|
|
430
|
+
type: "object",
|
|
431
|
+
properties: {
|
|
432
|
+
node_id: {
|
|
433
|
+
type: "string",
|
|
434
|
+
description: "Node ID of the clip",
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
required: ["node_id"],
|
|
438
|
+
},
|
|
439
|
+
handler: async (args) => {
|
|
440
|
+
const script = buildToolScript(`
|
|
441
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
442
|
+
if (!result) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
|
|
443
|
+
|
|
444
|
+
var clip = result.clip;
|
|
445
|
+
var speed = 1;
|
|
446
|
+
var reversed = false;
|
|
447
|
+
try { speed = clip.getSpeed(); } catch(e) {}
|
|
448
|
+
try { reversed = clip.isSpeedReversed() == 1; } catch(e) {}
|
|
449
|
+
|
|
450
|
+
return __result({
|
|
451
|
+
clipName: clip.name,
|
|
452
|
+
speed: speed,
|
|
453
|
+
reversed: reversed
|
|
454
|
+
});
|
|
455
|
+
`);
|
|
456
|
+
return sendCommand(script, bridgeOptions);
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
set_clip_selection: {
|
|
460
|
+
description: "Select or deselect a clip in the active sequence",
|
|
461
|
+
parameters: {
|
|
462
|
+
type: "object",
|
|
463
|
+
properties: {
|
|
464
|
+
node_id: {
|
|
465
|
+
type: "string",
|
|
466
|
+
description: "Node ID of the clip",
|
|
467
|
+
},
|
|
468
|
+
selected: {
|
|
469
|
+
type: "boolean",
|
|
470
|
+
description: "True to select, false to deselect",
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
required: ["node_id", "selected"],
|
|
474
|
+
},
|
|
475
|
+
handler: async (args) => {
|
|
476
|
+
const script = buildToolScript(`
|
|
477
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
478
|
+
if (!result) return __error("Clip not found");
|
|
479
|
+
|
|
480
|
+
result.clip.setSelected(${args.selected ? 1 : 0}, true);
|
|
481
|
+
return __result({ selected: ${args.selected}, clipName: result.clip.name });
|
|
482
|
+
`);
|
|
483
|
+
return sendCommand(script, bridgeOptions);
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
link_selection: {
|
|
487
|
+
description: "Link the currently selected video and audio clips in the active sequence",
|
|
488
|
+
parameters: {},
|
|
489
|
+
handler: async () => {
|
|
490
|
+
const script = buildToolScript(`
|
|
491
|
+
var seq = app.project.activeSequence;
|
|
492
|
+
if (!seq) return __error("No active sequence");
|
|
493
|
+
seq.linkSelection();
|
|
494
|
+
return __result({ linked: true });
|
|
495
|
+
`);
|
|
496
|
+
return sendCommand(script, bridgeOptions);
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
unlink_selection: {
|
|
500
|
+
description: "Unlink the currently selected video and audio clips in the active sequence",
|
|
501
|
+
parameters: {},
|
|
502
|
+
handler: async () => {
|
|
503
|
+
const script = buildToolScript(`
|
|
504
|
+
var seq = app.project.activeSequence;
|
|
505
|
+
if (!seq) return __error("No active sequence");
|
|
506
|
+
seq.unlinkSelection();
|
|
507
|
+
return __result({ unlinked: true });
|
|
508
|
+
`);
|
|
509
|
+
return sendCommand(script, bridgeOptions);
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
overwrite_clip: {
|
|
513
|
+
description: "Overwrite a project item onto the timeline (replaces existing clips at the insertion point)",
|
|
514
|
+
parameters: {
|
|
515
|
+
type: "object",
|
|
516
|
+
properties: {
|
|
517
|
+
item_id: {
|
|
518
|
+
type: "string",
|
|
519
|
+
description: "Node ID or name of the project item to add",
|
|
520
|
+
},
|
|
521
|
+
start_seconds: {
|
|
522
|
+
type: "number",
|
|
523
|
+
description: "Start time in seconds on the timeline (default: 0)",
|
|
524
|
+
},
|
|
525
|
+
track_index: {
|
|
526
|
+
type: "number",
|
|
527
|
+
description: "Video track index (0-based, default: 0)",
|
|
528
|
+
},
|
|
529
|
+
audio_track_index: {
|
|
530
|
+
type: "number",
|
|
531
|
+
description: "Audio track index (0-based, default: 0)",
|
|
532
|
+
},
|
|
533
|
+
},
|
|
534
|
+
required: ["item_id"],
|
|
535
|
+
},
|
|
536
|
+
handler: async (args) => {
|
|
537
|
+
const startSeconds = args.start_seconds ?? 0;
|
|
538
|
+
const trackIndex = args.track_index ?? 0;
|
|
539
|
+
const audioTrackIndex = args.audio_track_index ?? 0;
|
|
540
|
+
const script = buildToolScript(`
|
|
541
|
+
var seq = app.project.activeSequence;
|
|
542
|
+
if (!seq) return __error("No active sequence");
|
|
543
|
+
|
|
544
|
+
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
|
545
|
+
if (!item) return __error("Project item not found: ${escapeForExtendScript(args.item_id)}");
|
|
546
|
+
|
|
547
|
+
var startTicks = __secondsToTicks(${startSeconds}).toString();
|
|
548
|
+
seq.overwriteClip(item, startTicks, ${trackIndex}, ${audioTrackIndex});
|
|
549
|
+
|
|
550
|
+
return __result({
|
|
551
|
+
overwritten: true,
|
|
552
|
+
item: item.name,
|
|
553
|
+
trackIndex: ${trackIndex},
|
|
554
|
+
startSeconds: ${startSeconds}
|
|
555
|
+
});
|
|
556
|
+
`);
|
|
557
|
+
return sendCommand(script, bridgeOptions);
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
create_sequence_from_clips: {
|
|
561
|
+
description: "Create a new sequence by automatically placing project items in order",
|
|
562
|
+
parameters: {
|
|
563
|
+
type: "object",
|
|
564
|
+
properties: {
|
|
565
|
+
name: {
|
|
566
|
+
type: "string",
|
|
567
|
+
description: "Name for the new sequence",
|
|
568
|
+
},
|
|
569
|
+
item_ids: {
|
|
570
|
+
type: "array",
|
|
571
|
+
description: "Array of project item names or node IDs to include in order",
|
|
572
|
+
},
|
|
573
|
+
},
|
|
574
|
+
required: ["name", "item_ids"],
|
|
575
|
+
},
|
|
576
|
+
handler: async (args) => {
|
|
577
|
+
const itemLookups = args.item_ids
|
|
578
|
+
.map((id, i) => `var item${i} = __findProjectItem("${escapeForExtendScript(id)}"); if (!item${i}) return __error("Item not found: ${escapeForExtendScript(id)}"); items.push(item${i});`)
|
|
579
|
+
.join("\n ");
|
|
580
|
+
const script = buildToolScript(`
|
|
581
|
+
var items = [];
|
|
582
|
+
${itemLookups}
|
|
583
|
+
|
|
584
|
+
// PP 2026: pass rootItem as third argument (required for correct bin placement)
|
|
585
|
+
var seq = app.project.createNewSequenceFromClips("${escapeForExtendScript(args.name)}", items, app.project.rootItem);
|
|
586
|
+
if (!seq) return __error("Failed to create sequence from clips");
|
|
587
|
+
return __result({ created: true, name: seq.name, id: seq.sequenceID, clipCount: items.length });
|
|
588
|
+
`);
|
|
589
|
+
return sendCommand(script, bridgeOptions);
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
close_sequence: {
|
|
593
|
+
description: "Close a sequence tab in the timeline",
|
|
594
|
+
parameters: {
|
|
595
|
+
type: "object",
|
|
596
|
+
properties: {
|
|
597
|
+
sequence_id: {
|
|
598
|
+
type: "string",
|
|
599
|
+
description: "Sequence name or ID. Uses active sequence if omitted.",
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
handler: async (args) => {
|
|
604
|
+
const seqLookup = args.sequence_id
|
|
605
|
+
? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
|
|
606
|
+
: `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
|
|
607
|
+
const script = buildToolScript(`
|
|
608
|
+
${seqLookup}
|
|
609
|
+
var name = seq.name;
|
|
610
|
+
seq.close();
|
|
611
|
+
return __result({ closed: true, name: name });
|
|
612
|
+
`);
|
|
613
|
+
return sendCommand(script, bridgeOptions);
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
export_as_project: {
|
|
617
|
+
description: "Export a sequence as a standalone Premiere Pro project file",
|
|
618
|
+
parameters: {
|
|
619
|
+
type: "object",
|
|
620
|
+
properties: {
|
|
621
|
+
sequence_id: {
|
|
622
|
+
type: "string",
|
|
623
|
+
description: "Sequence name or ID. Uses active sequence if omitted.",
|
|
624
|
+
},
|
|
625
|
+
output_path: {
|
|
626
|
+
type: "string",
|
|
627
|
+
description: "Full path for the exported .prproj file",
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
required: ["output_path"],
|
|
631
|
+
},
|
|
632
|
+
handler: async (args) => {
|
|
633
|
+
const seqLookup = args.sequence_id
|
|
634
|
+
? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
|
|
635
|
+
: `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
|
|
636
|
+
const script = buildToolScript(`
|
|
637
|
+
${seqLookup}
|
|
638
|
+
seq.exportAsProject("${escapeForExtendScript(args.output_path)}");
|
|
639
|
+
return __result({ exported: true, path: "${escapeForExtendScript(args.output_path)}" });
|
|
640
|
+
`);
|
|
641
|
+
return sendCommand(script, bridgeOptions);
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
set_zero_point: {
|
|
645
|
+
description: "Set the starting timecode (zero point) of a sequence",
|
|
646
|
+
parameters: {
|
|
647
|
+
type: "object",
|
|
648
|
+
properties: {
|
|
649
|
+
sequence_id: {
|
|
650
|
+
type: "string",
|
|
651
|
+
description: "Sequence name or ID. Uses active sequence if omitted.",
|
|
652
|
+
},
|
|
653
|
+
start_seconds: {
|
|
654
|
+
type: "number",
|
|
655
|
+
description: "Start time in seconds for the timecode origin",
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
required: ["start_seconds"],
|
|
659
|
+
},
|
|
660
|
+
handler: async (args) => {
|
|
661
|
+
const seqLookup = args.sequence_id
|
|
662
|
+
? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
|
|
663
|
+
: `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
|
|
664
|
+
const script = buildToolScript(`
|
|
665
|
+
${seqLookup}
|
|
666
|
+
var ticks = __secondsToTicks(${args.start_seconds}).toString();
|
|
667
|
+
seq.setZeroPoint(ticks);
|
|
668
|
+
return __result({ set: true, startSeconds: ${args.start_seconds} });
|
|
669
|
+
`);
|
|
670
|
+
return sendCommand(script, bridgeOptions);
|
|
671
|
+
},
|
|
672
|
+
},
|
|
673
|
+
scene_edit_detection: {
|
|
674
|
+
description: "Perform scene edit detection on the selected clips in the active sequence",
|
|
675
|
+
parameters: {},
|
|
676
|
+
handler: async () => {
|
|
677
|
+
const script = buildToolScript(`
|
|
678
|
+
var seq = app.project.activeSequence;
|
|
679
|
+
if (!seq) return __error("No active sequence");
|
|
680
|
+
seq.performSceneEditDetectionOnSelection();
|
|
681
|
+
return __result({ sceneDetection: true });
|
|
682
|
+
`);
|
|
683
|
+
return sendCommand(script, bridgeOptions);
|
|
684
|
+
},
|
|
685
|
+
},
|
|
686
|
+
delete_preview_files: {
|
|
687
|
+
description: "Delete all preview/render cache files for the project. Uses QE DOM.",
|
|
688
|
+
parameters: {
|
|
689
|
+
type: "object",
|
|
690
|
+
properties: {
|
|
691
|
+
media_type: {
|
|
692
|
+
type: "string",
|
|
693
|
+
description: "Type of preview files to delete: 'video', 'audio', or 'all' (default: 'all')",
|
|
694
|
+
},
|
|
695
|
+
},
|
|
696
|
+
},
|
|
697
|
+
handler: async (args) => {
|
|
698
|
+
const typeMap = {
|
|
699
|
+
video: '"228CDA18-3625-4d2d-951E-348879E4ED93"',
|
|
700
|
+
audio: '"80B8E3D5-6DCA-4195-AEFB-CB5F407AB009"',
|
|
701
|
+
all: '"FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"',
|
|
702
|
+
};
|
|
703
|
+
const mediaType = typeMap[args.media_type || "all"] || typeMap.all;
|
|
704
|
+
const script = buildToolScript(`
|
|
705
|
+
app.enableQE();
|
|
706
|
+
qe.project.deletePreviewFiles(${mediaType});
|
|
707
|
+
return __result({ deleted: true, mediaType: "${args.media_type || "all"}" });
|
|
708
|
+
`);
|
|
709
|
+
return sendCommand(script, bridgeOptions);
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
add_tracks: {
|
|
713
|
+
description: "Add video and/or audio tracks to the active sequence. Uses QE DOM.",
|
|
714
|
+
parameters: {
|
|
715
|
+
type: "object",
|
|
716
|
+
properties: {
|
|
717
|
+
video_tracks: {
|
|
718
|
+
type: "number",
|
|
719
|
+
description: "Number of video tracks to add (default: 0)",
|
|
720
|
+
},
|
|
721
|
+
audio_tracks: {
|
|
722
|
+
type: "number",
|
|
723
|
+
description: "Number of standard stereo audio tracks to add (default: 0)",
|
|
724
|
+
},
|
|
725
|
+
audio_mono_tracks: {
|
|
726
|
+
type: "number",
|
|
727
|
+
description: "Number of mono audio tracks to add (default: 0)",
|
|
728
|
+
},
|
|
729
|
+
audio_51_tracks: {
|
|
730
|
+
type: "number",
|
|
731
|
+
description: "Number of 5.1 audio tracks to add (default: 0)",
|
|
732
|
+
},
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
handler: async (args) => {
|
|
736
|
+
const v = args.video_tracks ?? 0;
|
|
737
|
+
const a = args.audio_tracks ?? 0;
|
|
738
|
+
const aMono = args.audio_mono_tracks ?? 0;
|
|
739
|
+
const a51 = args.audio_51_tracks ?? 0;
|
|
740
|
+
const script = buildToolScript(`
|
|
741
|
+
app.enableQE();
|
|
742
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
743
|
+
if (!qeSeq) return __error("No active sequence (QE)");
|
|
744
|
+
|
|
745
|
+
qeSeq.addTracks(${v}, ${a}, ${aMono}, ${a51});
|
|
746
|
+
return __result({
|
|
747
|
+
added: true,
|
|
748
|
+
videoTracks: ${v},
|
|
749
|
+
audioTracks: ${a},
|
|
750
|
+
audioMonoTracks: ${aMono},
|
|
751
|
+
audio51Tracks: ${a51}
|
|
752
|
+
});
|
|
753
|
+
`);
|
|
754
|
+
return sendCommand(script, bridgeOptions);
|
|
755
|
+
},
|
|
756
|
+
},
|
|
757
|
+
set_color_value: {
|
|
758
|
+
description: "Set a color value on an effect property (e.g., tint color, fill color)",
|
|
759
|
+
parameters: {
|
|
760
|
+
type: "object",
|
|
761
|
+
properties: {
|
|
762
|
+
node_id: {
|
|
763
|
+
type: "string",
|
|
764
|
+
description: "Node ID of the clip",
|
|
765
|
+
},
|
|
766
|
+
component_name: {
|
|
767
|
+
type: "string",
|
|
768
|
+
description: "Name of the component/effect",
|
|
769
|
+
},
|
|
770
|
+
property_name: {
|
|
771
|
+
type: "string",
|
|
772
|
+
description: "Name of the color property",
|
|
773
|
+
},
|
|
774
|
+
alpha: {
|
|
775
|
+
type: "number",
|
|
776
|
+
description: "Alpha (0-255)",
|
|
777
|
+
},
|
|
778
|
+
red: {
|
|
779
|
+
type: "number",
|
|
780
|
+
description: "Red (0-255)",
|
|
781
|
+
},
|
|
782
|
+
green: {
|
|
783
|
+
type: "number",
|
|
784
|
+
description: "Green (0-255)",
|
|
785
|
+
},
|
|
786
|
+
blue: {
|
|
787
|
+
type: "number",
|
|
788
|
+
description: "Blue (0-255)",
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
required: ["node_id", "component_name", "property_name", "alpha", "red", "green", "blue"],
|
|
792
|
+
},
|
|
793
|
+
handler: async (args) => {
|
|
794
|
+
const script = buildToolScript(`
|
|
795
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
796
|
+
if (!result) return __error("Clip not found");
|
|
797
|
+
|
|
798
|
+
var clip = result.clip;
|
|
799
|
+
var components = clip.components;
|
|
800
|
+
var targetComp = null;
|
|
801
|
+
for (var i = 0; i < components.numItems; i++) {
|
|
802
|
+
if (components[i].displayName === "${escapeForExtendScript(args.component_name)}") {
|
|
803
|
+
targetComp = components[i];
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
if (!targetComp) return __error("Component not found");
|
|
808
|
+
|
|
809
|
+
var targetProp = null;
|
|
810
|
+
for (var j = 0; j < targetComp.properties.numItems; j++) {
|
|
811
|
+
if (targetComp.properties[j].displayName === "${escapeForExtendScript(args.property_name)}") {
|
|
812
|
+
targetProp = targetComp.properties[j];
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
if (!targetProp) return __error("Property not found");
|
|
817
|
+
|
|
818
|
+
targetProp.setColorValue(${args.alpha}, ${args.red}, ${args.green}, ${args.blue}, true);
|
|
819
|
+
return __result({
|
|
820
|
+
set: true,
|
|
821
|
+
color: { alpha: ${args.alpha}, red: ${args.red}, green: ${args.green}, blue: ${args.blue} }
|
|
822
|
+
});
|
|
823
|
+
`);
|
|
824
|
+
return sendCommand(script, bridgeOptions);
|
|
825
|
+
},
|
|
826
|
+
},
|
|
827
|
+
get_clip_adjustment_layer: {
|
|
828
|
+
description: "Check if a clip is an adjustment layer",
|
|
829
|
+
parameters: {
|
|
830
|
+
type: "object",
|
|
831
|
+
properties: {
|
|
832
|
+
node_id: {
|
|
833
|
+
type: "string",
|
|
834
|
+
description: "Node ID of the clip",
|
|
835
|
+
},
|
|
836
|
+
},
|
|
837
|
+
required: ["node_id"],
|
|
838
|
+
},
|
|
839
|
+
handler: async (args) => {
|
|
840
|
+
const script = buildToolScript(`
|
|
841
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
842
|
+
if (!result) return __error("Clip not found");
|
|
843
|
+
|
|
844
|
+
var clip = result.clip;
|
|
845
|
+
var isAdj = false;
|
|
846
|
+
try { isAdj = clip.isAdjustmentLayer(); } catch(e) {}
|
|
847
|
+
|
|
848
|
+
return __result({ clipName: clip.name, isAdjustmentLayer: isAdj });
|
|
849
|
+
`);
|
|
850
|
+
return sendCommand(script, bridgeOptions);
|
|
851
|
+
},
|
|
852
|
+
},
|
|
853
|
+
get_linked_items: {
|
|
854
|
+
description: "Get all clips in the sequence that are linked to the same source as a given clip",
|
|
855
|
+
parameters: {
|
|
856
|
+
type: "object",
|
|
857
|
+
properties: {
|
|
858
|
+
node_id: {
|
|
859
|
+
type: "string",
|
|
860
|
+
description: "Node ID of the clip",
|
|
861
|
+
},
|
|
862
|
+
},
|
|
863
|
+
required: ["node_id"],
|
|
864
|
+
},
|
|
865
|
+
handler: async (args) => {
|
|
866
|
+
const script = buildToolScript(`
|
|
867
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
868
|
+
if (!result) return __error("Clip not found");
|
|
869
|
+
|
|
870
|
+
var linked = result.clip.getLinkedItems();
|
|
871
|
+
var items = [];
|
|
872
|
+
if (linked) {
|
|
873
|
+
for (var i = 0; i < linked.numItems; i++) {
|
|
874
|
+
items.push({
|
|
875
|
+
name: linked[i].name,
|
|
876
|
+
nodeId: linked[i].nodeId,
|
|
877
|
+
startSeconds: __ticksToSeconds(linked[i].start.ticks)
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return __result({ clipName: result.clip.name, linkedItems: items, count: items.length });
|
|
883
|
+
`);
|
|
884
|
+
return sendCommand(script, bridgeOptions);
|
|
885
|
+
},
|
|
886
|
+
},
|
|
887
|
+
get_mogrt_component: {
|
|
888
|
+
description: "Get MOGRT (Motion Graphics Template) component parameters from a clip",
|
|
889
|
+
parameters: {
|
|
890
|
+
type: "object",
|
|
891
|
+
properties: {
|
|
892
|
+
node_id: {
|
|
893
|
+
type: "string",
|
|
894
|
+
description: "Node ID of the MOGRT clip on the timeline",
|
|
895
|
+
},
|
|
896
|
+
},
|
|
897
|
+
required: ["node_id"],
|
|
898
|
+
},
|
|
899
|
+
handler: async (args) => {
|
|
900
|
+
const script = buildToolScript(`
|
|
901
|
+
var result = __findClip("${escapeForExtendScript(args.node_id)}");
|
|
902
|
+
if (!result) return __error("Clip not found");
|
|
903
|
+
|
|
904
|
+
var mgtComp = result.clip.getMGTComponent();
|
|
905
|
+
if (!mgtComp) return __error("Not a MOGRT clip or no MGT component found");
|
|
906
|
+
|
|
907
|
+
var params = [];
|
|
908
|
+
for (var i = 0; i < mgtComp.properties.numItems; i++) {
|
|
909
|
+
var p = mgtComp.properties[i];
|
|
910
|
+
params.push({
|
|
911
|
+
displayName: p.displayName,
|
|
912
|
+
value: p.getValue()
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
return __result({ clipName: result.clip.name, parameters: params });
|
|
917
|
+
`);
|
|
918
|
+
return sendCommand(script, bridgeOptions);
|
|
919
|
+
},
|
|
920
|
+
},
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
//# sourceMappingURL=advanced.js.map
|