@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,618 @@
|
|
|
1
|
+
import { buildToolScript, escapeForExtendScript } from "../bridge/script-builder.js";
|
|
2
|
+
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
import { readFileSync, unlinkSync, existsSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
export function getExportTools(bridgeOptions) {
|
|
7
|
+
return {
|
|
8
|
+
export_sequence: {
|
|
9
|
+
description: `Export the active sequence to a file using Adobe Media Encoder (AME).
|
|
10
|
+
|
|
11
|
+
Preconditions: An active sequence must exist. Adobe Media Encoder must be installed. The output directory must exist and be writable.
|
|
12
|
+
|
|
13
|
+
Export runs asynchronously via AME — this tool queues and starts the export, but completion may take minutes. The tool returns after the export job is queued (not after it finishes).
|
|
14
|
+
|
|
15
|
+
Common preset paths:
|
|
16
|
+
- macOS H.264 1080p: /Applications/Adobe Media Encoder [year]/MediaIO/systempresets/4028/HDTV 1080p 29.97 High Quality.epr
|
|
17
|
+
- Windows H.264: C:\\Program Files\\Adobe\\Adobe Media Encoder [year]\\MediaIO\\systempresets\\4028\\HDTV 1080p 29.97 High Quality.epr
|
|
18
|
+
|
|
19
|
+
If preset_path is omitted, uses default H.264 1080p settings.
|
|
20
|
+
|
|
21
|
+
Parameters:
|
|
22
|
+
- output_path: Absolute path for the output file including extension (e.g., .mp4, .mov, .mxf).
|
|
23
|
+
- preset_path: Path to an AME .epr preset file. Determines codec, bitrate, and format.
|
|
24
|
+
- work_area_only: If true, exports only the range between work area in/out points instead of the full sequence.
|
|
25
|
+
|
|
26
|
+
Example: export_sequence({ output_path: "C:\\\\Exports\\\\final.mp4" })
|
|
27
|
+
Example: export_sequence({ output_path: "/Users/me/exports/prores.mov", preset_path: "/path/to/ProRes422.epr", work_area_only: false })`,
|
|
28
|
+
parameters: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
output_path: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Full output file path (e.g., '/Users/me/exports/video.mp4')",
|
|
34
|
+
},
|
|
35
|
+
preset_path: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Path to an AME preset file (.epr). Uses default H.264 if omitted.",
|
|
38
|
+
},
|
|
39
|
+
work_area_only: {
|
|
40
|
+
type: "boolean",
|
|
41
|
+
description: "Export only the work area (default: false, exports entire sequence)",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ["output_path"],
|
|
45
|
+
},
|
|
46
|
+
handler: async (args) => {
|
|
47
|
+
const script = buildToolScript(`
|
|
48
|
+
var seq = app.project.activeSequence;
|
|
49
|
+
if (!seq) return __error("No active sequence");
|
|
50
|
+
|
|
51
|
+
var outputPath = "${escapeForExtendScript(args.output_path)}";
|
|
52
|
+
|
|
53
|
+
${args.preset_path
|
|
54
|
+
? `var presetPath = "${escapeForExtendScript(args.preset_path)}";`
|
|
55
|
+
: `// No preset_path provided — build a default by probing common locations.
|
|
56
|
+
var presetPath = "";
|
|
57
|
+
var presetCandidates = [
|
|
58
|
+
// Windows — Adobe Media Encoder 2026 / 2025 / 2024 / generic
|
|
59
|
+
"C:\\\\Program Files\\\\Adobe\\\\Adobe Media Encoder 2026\\\\MediaIO\\\\systempresets\\\\4028\\\\HDTV 1080p 29.97 High Quality.epr",
|
|
60
|
+
"C:\\\\Program Files\\\\Adobe\\\\Adobe Media Encoder 2025\\\\MediaIO\\\\systempresets\\\\4028\\\\HDTV 1080p 29.97 High Quality.epr",
|
|
61
|
+
"C:\\\\Program Files\\\\Adobe\\\\Adobe Media Encoder 2024\\\\MediaIO\\\\systempresets\\\\4028\\\\HDTV 1080p 29.97 High Quality.epr",
|
|
62
|
+
// macOS — Adobe Media Encoder 2026 / 2025 / 2024
|
|
63
|
+
"/Applications/Adobe Media Encoder 2026/MediaIO/systempresets/4028/HDTV 1080p 29.97 High Quality.epr",
|
|
64
|
+
"/Applications/Adobe Media Encoder 2025/MediaIO/systempresets/4028/HDTV 1080p 29.97 High Quality.epr",
|
|
65
|
+
"/Applications/Adobe Media Encoder 2024/MediaIO/systempresets/4028/HDTV 1080p 29.97 High Quality.epr"
|
|
66
|
+
];
|
|
67
|
+
for (var i = 0; i < presetCandidates.length; i++) {
|
|
68
|
+
var presetFile = new File(presetCandidates[i]);
|
|
69
|
+
if (presetFile.exists) { presetPath = presetFile.fsName; break; }
|
|
70
|
+
}
|
|
71
|
+
if (presetPath === "") {
|
|
72
|
+
return __error("No default export preset (.epr) could be found on this system. Pass preset_path with an absolute path to an AME .epr preset file.");
|
|
73
|
+
}`}
|
|
74
|
+
|
|
75
|
+
var exportResult = seq.exportAsMediaDirect(
|
|
76
|
+
outputPath,
|
|
77
|
+
presetPath,
|
|
78
|
+
${args.work_area_only ? "app.encoder.ENCODE_WORKAREA" : "app.encoder.ENCODE_ENTIRE"}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
return __result({ exported: true, outputPath: outputPath });
|
|
82
|
+
`);
|
|
83
|
+
return sendCommand(script, { ...bridgeOptions, timeoutMs: 120000 }); // 2 min timeout for exports
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
export_frame: {
|
|
87
|
+
description: "Export the current frame as an image file",
|
|
88
|
+
parameters: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
output_path: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: "Full output file path (e.g., '/Users/me/frame.png'). Extension determines format.",
|
|
94
|
+
},
|
|
95
|
+
time_seconds: {
|
|
96
|
+
type: "number",
|
|
97
|
+
description: "Time position in seconds to export. Uses current playhead if omitted.",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: ["output_path"],
|
|
101
|
+
},
|
|
102
|
+
handler: async (args) => {
|
|
103
|
+
const script = buildToolScript(`
|
|
104
|
+
var seq = app.project.activeSequence;
|
|
105
|
+
if (!seq) return __error("No active sequence");
|
|
106
|
+
|
|
107
|
+
${args.time_seconds !== undefined
|
|
108
|
+
? `seq.setPlayerPosition(__secondsToTicks(${args.time_seconds}).toString());`
|
|
109
|
+
: ""}
|
|
110
|
+
|
|
111
|
+
var outputPath = "${escapeForExtendScript(args.output_path)}";
|
|
112
|
+
seq.exportFramePNG(seq.getPlayerPosition().ticks, outputPath);
|
|
113
|
+
|
|
114
|
+
return __result({ exported: true, outputPath: outputPath });
|
|
115
|
+
`);
|
|
116
|
+
return sendCommand(script, bridgeOptions);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
export_as_fcp_xml: {
|
|
120
|
+
description: "Export the active sequence as a Final Cut Pro XML file",
|
|
121
|
+
parameters: {
|
|
122
|
+
type: "object",
|
|
123
|
+
properties: {
|
|
124
|
+
output_path: {
|
|
125
|
+
type: "string",
|
|
126
|
+
description: "Full output file path (e.g., '/Users/me/export.xml')",
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
required: ["output_path"],
|
|
130
|
+
},
|
|
131
|
+
handler: async (args) => {
|
|
132
|
+
const script = buildToolScript(`
|
|
133
|
+
var seq = app.project.activeSequence;
|
|
134
|
+
if (!seq) return __error("No active sequence");
|
|
135
|
+
|
|
136
|
+
seq.exportAsFinalCutProXML("${escapeForExtendScript(args.output_path)}");
|
|
137
|
+
return __result({ exported: true, outputPath: "${escapeForExtendScript(args.output_path)}", format: "FCP XML" });
|
|
138
|
+
`);
|
|
139
|
+
return sendCommand(script, bridgeOptions);
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
export_aaf: {
|
|
143
|
+
description: "Export the active sequence as an AAF file (for Pro Tools, etc.)",
|
|
144
|
+
parameters: {
|
|
145
|
+
type: "object",
|
|
146
|
+
properties: {
|
|
147
|
+
output_path: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "Full output file path (e.g., '/Users/me/export.aaf')",
|
|
150
|
+
},
|
|
151
|
+
mix_down_video: {
|
|
152
|
+
type: "boolean",
|
|
153
|
+
description: "Mix down video to single track (default: true)",
|
|
154
|
+
},
|
|
155
|
+
explode_to_mono: {
|
|
156
|
+
type: "boolean",
|
|
157
|
+
description: "Explode multichannel audio to mono (default: false)",
|
|
158
|
+
},
|
|
159
|
+
sample_rate: {
|
|
160
|
+
type: "number",
|
|
161
|
+
description: "Audio sample rate (default: 48000)",
|
|
162
|
+
},
|
|
163
|
+
bits_per_sample: {
|
|
164
|
+
type: "number",
|
|
165
|
+
description: "Audio bit depth (default: 16)",
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ["output_path"],
|
|
169
|
+
},
|
|
170
|
+
handler: async (args) => {
|
|
171
|
+
const script = buildToolScript(`
|
|
172
|
+
var seq = app.project.activeSequence;
|
|
173
|
+
if (!seq) return __error("No active sequence");
|
|
174
|
+
|
|
175
|
+
seq.exportAsAAF(
|
|
176
|
+
"${escapeForExtendScript(args.output_path)}",
|
|
177
|
+
${args.mix_down_video !== false ? 1 : 0},
|
|
178
|
+
${args.explode_to_mono ? 1 : 0},
|
|
179
|
+
${args.sample_rate ?? 48000},
|
|
180
|
+
${args.bits_per_sample ?? 16}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
return __result({ exported: true, outputPath: "${escapeForExtendScript(args.output_path)}", format: "AAF" });
|
|
184
|
+
`);
|
|
185
|
+
return sendCommand(script, bridgeOptions);
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
add_to_render_queue: {
|
|
189
|
+
description: "Add the active sequence to the Adobe Media Encoder render queue",
|
|
190
|
+
parameters: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
output_path: {
|
|
194
|
+
type: "string",
|
|
195
|
+
description: "Full output file path",
|
|
196
|
+
},
|
|
197
|
+
preset_path: {
|
|
198
|
+
type: "string",
|
|
199
|
+
description: "Path to an AME preset file (.epr)",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
required: ["output_path"],
|
|
203
|
+
},
|
|
204
|
+
handler: async (args) => {
|
|
205
|
+
const script = buildToolScript(`
|
|
206
|
+
var seq = app.project.activeSequence;
|
|
207
|
+
if (!seq) return __error("No active sequence");
|
|
208
|
+
|
|
209
|
+
var encoder = app.encoder;
|
|
210
|
+
if (!encoder) return __error("Adobe Media Encoder not available");
|
|
211
|
+
|
|
212
|
+
encoder.launchEncoder();
|
|
213
|
+
|
|
214
|
+
var outputPath = "${escapeForExtendScript(args.output_path)}";
|
|
215
|
+
${args.preset_path
|
|
216
|
+
? `var presetPath = "${escapeForExtendScript(args.preset_path)}";`
|
|
217
|
+
: `var presetPath = encoder.ENCODE_MATCH_SEQUENCE;`}
|
|
218
|
+
|
|
219
|
+
encoder.encodeSequence(
|
|
220
|
+
seq,
|
|
221
|
+
outputPath,
|
|
222
|
+
presetPath,
|
|
223
|
+
0, // workAreaType
|
|
224
|
+
1 // removeOnCompletion
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
return __result({ queued: true, outputPath: outputPath });
|
|
228
|
+
`);
|
|
229
|
+
return sendCommand(script, bridgeOptions);
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
get_render_queue_status: {
|
|
233
|
+
description: "Get the current status of the Adobe Media Encoder render queue",
|
|
234
|
+
parameters: {},
|
|
235
|
+
handler: async () => {
|
|
236
|
+
const script = buildToolScript(`
|
|
237
|
+
var encoder = app.encoder;
|
|
238
|
+
if (!encoder) return __error("Adobe Media Encoder not available");
|
|
239
|
+
|
|
240
|
+
return __result({
|
|
241
|
+
isRunning: encoder.isRunning ? encoder.isRunning() : "unknown",
|
|
242
|
+
info: "Check Adobe Media Encoder application for detailed queue status"
|
|
243
|
+
});
|
|
244
|
+
`);
|
|
245
|
+
return sendCommand(script, bridgeOptions);
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
create_subclip: {
|
|
249
|
+
description: "Create a subclip from a project item with in/out points",
|
|
250
|
+
parameters: {
|
|
251
|
+
type: "object",
|
|
252
|
+
properties: {
|
|
253
|
+
item_id: {
|
|
254
|
+
type: "string",
|
|
255
|
+
description: "Node ID or name of the source project item",
|
|
256
|
+
},
|
|
257
|
+
name: {
|
|
258
|
+
type: "string",
|
|
259
|
+
description: "Name for the subclip",
|
|
260
|
+
},
|
|
261
|
+
in_seconds: {
|
|
262
|
+
type: "number",
|
|
263
|
+
description: "In-point in seconds",
|
|
264
|
+
},
|
|
265
|
+
out_seconds: {
|
|
266
|
+
type: "number",
|
|
267
|
+
description: "Out-point in seconds",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
required: ["item_id", "name", "in_seconds", "out_seconds"],
|
|
271
|
+
},
|
|
272
|
+
handler: async (args) => {
|
|
273
|
+
const script = buildToolScript(`
|
|
274
|
+
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
|
275
|
+
if (!item) return __error("Item not found");
|
|
276
|
+
|
|
277
|
+
var inTicks = __secondsToTicks(${args.in_seconds}).toString();
|
|
278
|
+
var outTicks = __secondsToTicks(${args.out_seconds}).toString();
|
|
279
|
+
|
|
280
|
+
var subclip = item.createSubClip(
|
|
281
|
+
"${escapeForExtendScript(args.name)}",
|
|
282
|
+
inTicks,
|
|
283
|
+
outTicks,
|
|
284
|
+
0, // hasHardBoundaries
|
|
285
|
+
1, // takeVideo
|
|
286
|
+
1 // takeAudio
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
if (!subclip) return __error("Failed to create subclip");
|
|
290
|
+
return __result({ created: true, name: "${escapeForExtendScript(args.name)}", source: item.name });
|
|
291
|
+
`);
|
|
292
|
+
return sendCommand(script, bridgeOptions);
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
capture_frame: {
|
|
296
|
+
description: "Capture the current frame and return it as inline image data for the LLM to see. This lets the AI visually inspect the current state of the timeline.",
|
|
297
|
+
parameters: {
|
|
298
|
+
type: "object",
|
|
299
|
+
properties: {
|
|
300
|
+
time_seconds: {
|
|
301
|
+
type: "number",
|
|
302
|
+
description: "Time position in seconds to capture. Uses current playhead if omitted.",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
handler: async (args) => {
|
|
307
|
+
const tempPath = join(tmpdir(), `mcp_frame_capture_${Date.now()}.png`);
|
|
308
|
+
const escapedPath = escapeForExtendScript(tempPath);
|
|
309
|
+
const script = buildToolScript(`
|
|
310
|
+
var seq = app.project.activeSequence;
|
|
311
|
+
if (!seq) return __error("No active sequence");
|
|
312
|
+
|
|
313
|
+
${args.time_seconds !== undefined
|
|
314
|
+
? `seq.setPlayerPosition(__secondsToTicks(${args.time_seconds}).toString());`
|
|
315
|
+
: ""}
|
|
316
|
+
|
|
317
|
+
var outputPath = "${escapedPath}";
|
|
318
|
+
// seq.exportFramePNG does not exist in PP 2026. Use the QE DOM approach:
|
|
319
|
+
// app.enableQE(); qe.project.getActiveSequence().exportFrameJPG(ticks, path)
|
|
320
|
+
// falls back to source monitor PNG if that also fails.
|
|
321
|
+
// PP 2026 host bug verified at runtime: seq.exportFramePNG / exportFrameJPEG
|
|
322
|
+
// do NOT exist on the DOM Sequence object, and qe.project.getActiveSequence()
|
|
323
|
+
// exposes exportFramePNG as a "function" but the call returns successfully
|
|
324
|
+
// WITHOUT writing the file (waited 5s, file never appears).
|
|
325
|
+
// The only working frame-export path in PP 2026 is via Adobe Media Encoder
|
|
326
|
+
// with a single-frame preset, which is heavy and asynchronous.
|
|
327
|
+
// Return an honest error with a recommended workaround.
|
|
328
|
+
app.enableQE();
|
|
329
|
+
var pos = seq.getPlayerPosition();
|
|
330
|
+
var posTicks = pos ? pos.ticks : "0";
|
|
331
|
+
var attempted = [];
|
|
332
|
+
var hadAnyFunction = false;
|
|
333
|
+
try {
|
|
334
|
+
var qeSeq2 = qe.project.getActiveSequence();
|
|
335
|
+
if (qeSeq2 && typeof qeSeq2.exportFramePNG === "function") {
|
|
336
|
+
hadAnyFunction = true;
|
|
337
|
+
attempted.push("qeSeq.exportFramePNG(path, ticks)");
|
|
338
|
+
qeSeq2.exportFramePNG(outputPath, posTicks);
|
|
339
|
+
// Wait a moment in case PP is fast enough
|
|
340
|
+
$.sleep(800);
|
|
341
|
+
var f = new File(outputPath);
|
|
342
|
+
if (f.exists && f.length > 0) {
|
|
343
|
+
return __result({ exported: true, outputPath: outputPath, atTicks: posTicks });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
} catch (eQE) { attempted.push("qe error: " + eQE.toString()); }
|
|
347
|
+
|
|
348
|
+
return __error("capture_frame is not supported in Premiere Pro 2026 via ExtendScript. " +
|
|
349
|
+
"Verified at runtime: seq.exportFramePNG/exportFrameJPEG do not exist on the DOM Sequence, " +
|
|
350
|
+
"and qe.project.getActiveSequence().exportFramePNG reports success but never writes the file. " +
|
|
351
|
+
"Workaround: use 'File > Export > Media > Single Frame' in the Premiere Pro UI, " +
|
|
352
|
+
"or use export_sequence with a single-frame preset via AME (heavy/async). " +
|
|
353
|
+
"Attempted: [" + attempted.join("; ") + "]. hadFunction=" + hadAnyFunction);
|
|
354
|
+
`);
|
|
355
|
+
const result = await sendCommand(script, bridgeOptions);
|
|
356
|
+
if (!result.success)
|
|
357
|
+
return result;
|
|
358
|
+
// Read the exported PNG and return as base64 image content
|
|
359
|
+
// Wait a moment for the file to be written
|
|
360
|
+
let attempts = 0;
|
|
361
|
+
while (!existsSync(tempPath) && attempts < 20) {
|
|
362
|
+
await new Promise(r => setTimeout(r, 100));
|
|
363
|
+
attempts++;
|
|
364
|
+
}
|
|
365
|
+
if (!existsSync(tempPath)) {
|
|
366
|
+
return { success: false, error: "Frame export completed but file not found at: " + tempPath };
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const imageData = readFileSync(tempPath);
|
|
370
|
+
const base64 = imageData.toString("base64");
|
|
371
|
+
// Clean up temp file
|
|
372
|
+
try {
|
|
373
|
+
unlinkSync(tempPath);
|
|
374
|
+
}
|
|
375
|
+
catch { }
|
|
376
|
+
return {
|
|
377
|
+
success: true,
|
|
378
|
+
data: {
|
|
379
|
+
captured: true,
|
|
380
|
+
mimeType: "image/png",
|
|
381
|
+
base64: base64,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
catch (e) {
|
|
386
|
+
return { success: false, error: `Failed to read captured frame: ${e instanceof Error ? e.message : String(e)}` };
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
export_omf: {
|
|
391
|
+
description: "Export the active sequence as an OMF file (Open Media Framework, for audio post-production)",
|
|
392
|
+
parameters: {
|
|
393
|
+
type: "object",
|
|
394
|
+
properties: {
|
|
395
|
+
output_path: {
|
|
396
|
+
type: "string",
|
|
397
|
+
description: "Full output file path (e.g., '/Users/me/export.omf')",
|
|
398
|
+
},
|
|
399
|
+
sample_rate: {
|
|
400
|
+
type: "number",
|
|
401
|
+
description: "Audio sample rate (default: 48000)",
|
|
402
|
+
},
|
|
403
|
+
bits_per_sample: {
|
|
404
|
+
type: "number",
|
|
405
|
+
description: "Audio bit depth (default: 16)",
|
|
406
|
+
},
|
|
407
|
+
audio_encapsulated: {
|
|
408
|
+
type: "boolean",
|
|
409
|
+
description: "Embed audio in OMF (true) or reference external files (false). Default: true",
|
|
410
|
+
},
|
|
411
|
+
audio_file_format: {
|
|
412
|
+
type: "number",
|
|
413
|
+
description: "Audio format: 0=AIFF, 1=WAV. Default: 1",
|
|
414
|
+
},
|
|
415
|
+
trim_audio_files: {
|
|
416
|
+
type: "boolean",
|
|
417
|
+
description: "Trim audio to used range plus handles (default: true)",
|
|
418
|
+
},
|
|
419
|
+
handle_frames: {
|
|
420
|
+
type: "number",
|
|
421
|
+
description: "Handle length in frames when trimming (default: 1000)",
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
required: ["output_path"],
|
|
425
|
+
},
|
|
426
|
+
handler: async (args) => {
|
|
427
|
+
const script = buildToolScript(`
|
|
428
|
+
var seq = app.project.activeSequence;
|
|
429
|
+
if (!seq) return __error("No active sequence");
|
|
430
|
+
|
|
431
|
+
app.project.exportOMF(
|
|
432
|
+
seq,
|
|
433
|
+
"${escapeForExtendScript(args.output_path)}",
|
|
434
|
+
"OMFTitle",
|
|
435
|
+
${args.sample_rate ?? 48000},
|
|
436
|
+
${args.bits_per_sample ?? 16},
|
|
437
|
+
${args.audio_encapsulated !== false ? 1 : 0},
|
|
438
|
+
${args.audio_file_format ?? 1},
|
|
439
|
+
${args.trim_audio_files !== false ? 1 : 0},
|
|
440
|
+
${args.handle_frames ?? 1000}
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
return __result({ exported: true, outputPath: "${escapeForExtendScript(args.output_path)}", format: "OMF" });
|
|
444
|
+
`);
|
|
445
|
+
return sendCommand(script, { ...bridgeOptions, timeoutMs: 120000 });
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
encode_project_item: {
|
|
449
|
+
description: "Encode a specific project item (not a sequence) using Adobe Media Encoder",
|
|
450
|
+
parameters: {
|
|
451
|
+
type: "object",
|
|
452
|
+
properties: {
|
|
453
|
+
item_id: {
|
|
454
|
+
type: "string",
|
|
455
|
+
description: "Node ID or name of the project item to encode",
|
|
456
|
+
},
|
|
457
|
+
output_path: {
|
|
458
|
+
type: "string",
|
|
459
|
+
description: "Full output file path",
|
|
460
|
+
},
|
|
461
|
+
preset_path: {
|
|
462
|
+
type: "string",
|
|
463
|
+
description: "Path to an AME preset file (.epr)",
|
|
464
|
+
},
|
|
465
|
+
remove_on_completion: {
|
|
466
|
+
type: "boolean",
|
|
467
|
+
description: "Remove from queue on completion (default: true)",
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
required: ["item_id", "output_path", "preset_path"],
|
|
471
|
+
},
|
|
472
|
+
handler: async (args) => {
|
|
473
|
+
const script = buildToolScript(`
|
|
474
|
+
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
|
475
|
+
if (!item) return __error("Project item not found: ${escapeForExtendScript(args.item_id)}");
|
|
476
|
+
|
|
477
|
+
app.encoder.launchEncoder();
|
|
478
|
+
app.encoder.encodeProjectItem(
|
|
479
|
+
item,
|
|
480
|
+
"${escapeForExtendScript(args.output_path)}",
|
|
481
|
+
"${escapeForExtendScript(args.preset_path)}",
|
|
482
|
+
app.encoder.ENCODE_IN_TO_OUT,
|
|
483
|
+
${args.remove_on_completion !== false ? 1 : 0}
|
|
484
|
+
);
|
|
485
|
+
app.encoder.startBatch();
|
|
486
|
+
|
|
487
|
+
return __result({
|
|
488
|
+
queued: true,
|
|
489
|
+
item: item.name,
|
|
490
|
+
outputPath: "${escapeForExtendScript(args.output_path)}"
|
|
491
|
+
});
|
|
492
|
+
`);
|
|
493
|
+
return sendCommand(script, bridgeOptions);
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
encode_file: {
|
|
497
|
+
description: "Encode an external file (not in project) using Adobe Media Encoder",
|
|
498
|
+
parameters: {
|
|
499
|
+
type: "object",
|
|
500
|
+
properties: {
|
|
501
|
+
input_path: {
|
|
502
|
+
type: "string",
|
|
503
|
+
description: "Full path to the input file",
|
|
504
|
+
},
|
|
505
|
+
output_path: {
|
|
506
|
+
type: "string",
|
|
507
|
+
description: "Full output file path",
|
|
508
|
+
},
|
|
509
|
+
preset_path: {
|
|
510
|
+
type: "string",
|
|
511
|
+
description: "Path to an AME preset file (.epr)",
|
|
512
|
+
},
|
|
513
|
+
in_seconds: {
|
|
514
|
+
type: "number",
|
|
515
|
+
description: "Optional start time in seconds",
|
|
516
|
+
},
|
|
517
|
+
out_seconds: {
|
|
518
|
+
type: "number",
|
|
519
|
+
description: "Optional end time in seconds",
|
|
520
|
+
},
|
|
521
|
+
remove_on_completion: {
|
|
522
|
+
type: "boolean",
|
|
523
|
+
description: "Remove from queue on completion (default: true)",
|
|
524
|
+
},
|
|
525
|
+
},
|
|
526
|
+
required: ["input_path", "output_path", "preset_path"],
|
|
527
|
+
},
|
|
528
|
+
handler: async (args) => {
|
|
529
|
+
const inPointCode = args.in_seconds !== undefined
|
|
530
|
+
? `var srcIn = new Time(); srcIn.seconds = ${args.in_seconds};`
|
|
531
|
+
: `var srcIn = undefined;`;
|
|
532
|
+
const outPointCode = args.out_seconds !== undefined
|
|
533
|
+
? `var srcOut = new Time(); srcOut.seconds = ${args.out_seconds};`
|
|
534
|
+
: `var srcOut = undefined;`;
|
|
535
|
+
const script = buildToolScript(`
|
|
536
|
+
app.encoder.launchEncoder();
|
|
537
|
+
|
|
538
|
+
${inPointCode}
|
|
539
|
+
${outPointCode}
|
|
540
|
+
|
|
541
|
+
// Signature: encodeFile(inputPath, outputPath, presetPath, workArea,
|
|
542
|
+
// removeUponCompletion, inPoint, outPoint). workArea 1 = in-to-out, 0 = entire.
|
|
543
|
+
var workArea = (typeof srcIn !== "undefined" || typeof srcOut !== "undefined") ? 1 : 0;
|
|
544
|
+
app.encoder.encodeFile(
|
|
545
|
+
"${escapeForExtendScript(args.input_path)}",
|
|
546
|
+
"${escapeForExtendScript(args.output_path)}",
|
|
547
|
+
"${escapeForExtendScript(args.preset_path)}",
|
|
548
|
+
workArea,
|
|
549
|
+
${args.remove_on_completion !== false ? 1 : 0},
|
|
550
|
+
srcIn,
|
|
551
|
+
srcOut
|
|
552
|
+
);
|
|
553
|
+
app.encoder.startBatch();
|
|
554
|
+
|
|
555
|
+
return __result({
|
|
556
|
+
queued: true,
|
|
557
|
+
inputPath: "${escapeForExtendScript(args.input_path)}",
|
|
558
|
+
outputPath: "${escapeForExtendScript(args.output_path)}"
|
|
559
|
+
});
|
|
560
|
+
`);
|
|
561
|
+
return sendCommand(script, bridgeOptions);
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
manage_proxies: {
|
|
565
|
+
description: "Create or attach proxies for a project item",
|
|
566
|
+
parameters: {
|
|
567
|
+
type: "object",
|
|
568
|
+
properties: {
|
|
569
|
+
item_id: {
|
|
570
|
+
type: "string",
|
|
571
|
+
description: "Node ID or name of the project item",
|
|
572
|
+
},
|
|
573
|
+
action: {
|
|
574
|
+
type: "string",
|
|
575
|
+
enum: ["create", "attach", "toggle"],
|
|
576
|
+
description: "Action to perform on proxies",
|
|
577
|
+
},
|
|
578
|
+
proxy_path: {
|
|
579
|
+
type: "string",
|
|
580
|
+
description: "Path to proxy file (required for 'attach' action)",
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
required: ["item_id", "action"],
|
|
584
|
+
},
|
|
585
|
+
handler: async (args) => {
|
|
586
|
+
const script = buildToolScript(`
|
|
587
|
+
var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
|
|
588
|
+
if (!item) return __error("Item not found");
|
|
589
|
+
|
|
590
|
+
var action = "${args.action}";
|
|
591
|
+
|
|
592
|
+
if (action === "create") {
|
|
593
|
+
item.createProxy("", 0);
|
|
594
|
+
return __result({ action: "create", item: item.name, status: "Proxy creation started" });
|
|
595
|
+
} else if (action === "attach") {
|
|
596
|
+
${args.proxy_path
|
|
597
|
+
? `item.attachProxy("${escapeForExtendScript(args.proxy_path)}", 0);
|
|
598
|
+
return __result({ action: "attach", item: item.name, proxyPath: "${escapeForExtendScript(args.proxy_path)}" });`
|
|
599
|
+
: `return __error("proxy_path is required for attach action");`}
|
|
600
|
+
} else if (action === "toggle") {
|
|
601
|
+
var hasP = false;
|
|
602
|
+
try { hasP = item.hasProxy(); } catch(e) {}
|
|
603
|
+
if (hasP) {
|
|
604
|
+
try { item.detachProxy(); } catch(e) {}
|
|
605
|
+
return __result({ action: "toggle", item: item.name, result: "proxy detached" });
|
|
606
|
+
} else {
|
|
607
|
+
return __result({ action: "toggle", item: item.name, result: "no proxy attached — use action='attach' with a proxy_path to add one" });
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
return __error("Unknown proxy action: " + action);
|
|
612
|
+
`);
|
|
613
|
+
return sendCommand(script, bridgeOptions);
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BridgeOptions } from "../bridge/file-bridge.js";
|
|
2
|
+
export declare function getHealthTools(bridgeOptions: BridgeOptions): {
|
|
3
|
+
ping: {
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: {};
|
|
6
|
+
handler: () => Promise<import("../bridge/file-bridge.js").CommandResult>;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { buildToolScript } from "../bridge/script-builder.js";
|
|
2
|
+
import { sendCommand } from "../bridge/file-bridge.js";
|
|
3
|
+
export function getHealthTools(bridgeOptions) {
|
|
4
|
+
return {
|
|
5
|
+
ping: {
|
|
6
|
+
description: "Health check — verify the CEP plugin is running and connected to Premiere Pro. Call this before other tools to confirm connectivity.",
|
|
7
|
+
parameters: {},
|
|
8
|
+
handler: async () => {
|
|
9
|
+
const script = buildToolScript(`
|
|
10
|
+
var version = app.version;
|
|
11
|
+
var projectName = app.project && app.project.name ? app.project.name : "No project open";
|
|
12
|
+
var activeSeq = app.project && app.project.activeSequence ? app.project.activeSequence.name : "None";
|
|
13
|
+
return __result({
|
|
14
|
+
connected: true,
|
|
15
|
+
premiereVersion: version,
|
|
16
|
+
projectName: projectName,
|
|
17
|
+
activeSequence: activeSeq
|
|
18
|
+
});
|
|
19
|
+
`);
|
|
20
|
+
return sendCommand(script, { ...bridgeOptions, timeoutMs: 5000 });
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=health.js.map
|