@synthetic-ai/premiere-mcp 2.2.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +135 -135
  2. package/LICENSE +21 -21
  3. package/README.md +242 -242
  4. package/cep-plugin/.debug +8 -8
  5. package/cep-plugin/CSInterface.js +92 -92
  6. package/cep-plugin/host.jsx +7 -7
  7. package/cep-plugin/index.html +472 -472
  8. package/cep-plugin/main.js +6 -0
  9. package/cep-plugin/premiere.jsx +24947 -24947
  10. package/dist/bridge/script-builder.js +378 -378
  11. package/dist/license.js +38 -0
  12. package/dist/server.js +60 -60
  13. package/dist/tools/advanced.js +357 -357
  14. package/dist/tools/audio-advanced.js +1049 -1049
  15. package/dist/tools/audio.js +42 -42
  16. package/dist/tools/captions.js +27 -27
  17. package/dist/tools/clipboard.js +214 -214
  18. package/dist/tools/color-advanced.js +253 -253
  19. package/dist/tools/discovery.js +291 -291
  20. package/dist/tools/effects.js +285 -285
  21. package/dist/tools/export-presets.js +206 -206
  22. package/dist/tools/export.js +255 -255
  23. package/dist/tools/health.js +10 -10
  24. package/dist/tools/inspection.js +885 -885
  25. package/dist/tools/keyframes.js +369 -369
  26. package/dist/tools/markers.js +89 -89
  27. package/dist/tools/media.js +178 -178
  28. package/dist/tools/metadata.js +94 -94
  29. package/dist/tools/multicam.js +50 -50
  30. package/dist/tools/playback.js +15 -15
  31. package/dist/tools/playhead.js +95 -95
  32. package/dist/tools/project-manager.js +21 -21
  33. package/dist/tools/project.js +149 -149
  34. package/dist/tools/scripting.js +319 -319
  35. package/dist/tools/selection.js +202 -202
  36. package/dist/tools/sequence-advanced.js +379 -379
  37. package/dist/tools/sequence-settings.js +564 -564
  38. package/dist/tools/sequence.js +167 -167
  39. package/dist/tools/source-monitor.js +68 -68
  40. package/dist/tools/text.js +58 -58
  41. package/dist/tools/timeline.js +312 -312
  42. package/dist/tools/track-management.js +446 -446
  43. package/dist/tools/track-targeting.js +635 -635
  44. package/dist/tools/tracks.js +87 -87
  45. package/dist/tools/transitions-motion.js +174 -174
  46. package/dist/tools/transitions.js +111 -111
  47. package/dist/tools/utility.js +606 -606
  48. package/dist/tools/workspace.js +29 -29
  49. package/package.json +66 -66
  50. package/scripts/build-chat-dmg.sh +210 -210
  51. package/scripts/build-chat-zip.sh +291 -291
  52. package/scripts/install-cep-windows.ps1 +99 -99
  53. package/scripts/install-cep.sh +66 -66
  54. package/scripts/install-chat-plugin.bat +67 -67
  55. package/scripts/install-chat-plugin.sh +85 -85
  56. package/scripts/install-windows.bat +95 -95
  57. package/scripts/package.mjs +254 -254
@@ -6,90 +6,90 @@ export function getInspectionTools(bridgeOptions) {
6
6
  description: "Get a comprehensive overview of the entire project: all bins (recursive tree), all sequences, media stats, offline items, and project settings. This is the best first call to fully understand a project.",
7
7
  parameters: {},
8
8
  handler: async () => {
9
- const script = buildToolScript(`
10
- var project = app.project;
11
- if (!project) return __error("No project is open");
12
-
13
- function walkBin(bin, depth) {
14
- var items = [];
15
- for (var i = 0; i < bin.children.numItems; i++) {
16
- var item = bin.children[i];
17
- var entry = {
18
- nodeId: item.nodeId,
19
- name: item.name,
20
- treePath: item.treePath,
21
- type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 3 ? "root" : item.type === 4 ? "file" : "unknown"
22
- };
23
- try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
24
- try { entry.offline = item.isOffline(); } catch(e) {}
25
- try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
26
- if (item.type === 2 && depth < 10) {
27
- entry.children = walkBin(item, depth + 1);
28
- entry.childCount = entry.children.length;
29
- }
30
- items.push(entry);
31
- }
32
- return items;
33
- }
34
-
35
- var binTree = walkBin(project.rootItem, 0);
36
-
37
- var sequences = [];
38
- for (var i = 0; i < project.sequences.numSequences; i++) {
39
- var seq = project.sequences[i];
40
- var clipCount = 0;
41
- for (var t = 0; t < seq.videoTracks.numTracks; t++) clipCount += seq.videoTracks[t].clips.numItems;
42
- for (var t = 0; t < seq.audioTracks.numTracks; t++) clipCount += seq.audioTracks[t].clips.numItems;
43
- sequences.push({
44
- name: seq.name,
45
- id: seq.sequenceID,
46
- width: seq.frameSizeHorizontal,
47
- height: seq.frameSizeVertical,
48
- durationSeconds: __ticksToSeconds(seq.end),
49
- videoTracks: seq.videoTracks.numTracks,
50
- audioTracks: seq.audioTracks.numTracks,
51
- totalClips: clipCount
52
- });
53
- }
54
-
55
- var totalItems = 0;
56
- var offlineCount = 0;
57
- var mediaTypes = {};
58
- function countItems(bin) {
59
- for (var i = 0; i < bin.children.numItems; i++) {
60
- var item = bin.children[i];
61
- totalItems++;
62
- try { if (item.isOffline()) offlineCount++; } catch(e) {}
63
- try {
64
- var mp = item.getMediaPath();
65
- if (mp) {
66
- var ext = mp.split(".").pop().toLowerCase();
67
- if (!mediaTypes[ext]) mediaTypes[ext] = 0;
68
- mediaTypes[ext]++;
69
- }
70
- } catch(e) {}
71
- if (item.type === 2) countItems(item);
72
- }
73
- }
74
- countItems(project.rootItem);
75
-
76
- var activeSeqInfo = null;
77
- var active = project.activeSequence;
78
- if (active) {
79
- activeSeqInfo = { name: active.name, id: active.sequenceID };
80
- }
81
-
82
- return __result({
83
- projectName: project.name,
84
- projectPath: project.path,
85
- totalItems: totalItems,
86
- offlineItems: offlineCount,
87
- sequenceCount: sequences.length,
88
- mediaFileTypes: mediaTypes,
89
- activeSequence: activeSeqInfo,
90
- sequences: sequences,
91
- binTree: binTree
92
- });
9
+ const script = buildToolScript(`
10
+ var project = app.project;
11
+ if (!project) return __error("No project is open");
12
+
13
+ function walkBin(bin, depth) {
14
+ var items = [];
15
+ for (var i = 0; i < bin.children.numItems; i++) {
16
+ var item = bin.children[i];
17
+ var entry = {
18
+ nodeId: item.nodeId,
19
+ name: item.name,
20
+ treePath: item.treePath,
21
+ type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 3 ? "root" : item.type === 4 ? "file" : "unknown"
22
+ };
23
+ try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
24
+ try { entry.offline = item.isOffline(); } catch(e) {}
25
+ try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
26
+ if (item.type === 2 && depth < 10) {
27
+ entry.children = walkBin(item, depth + 1);
28
+ entry.childCount = entry.children.length;
29
+ }
30
+ items.push(entry);
31
+ }
32
+ return items;
33
+ }
34
+
35
+ var binTree = walkBin(project.rootItem, 0);
36
+
37
+ var sequences = [];
38
+ for (var i = 0; i < project.sequences.numSequences; i++) {
39
+ var seq = project.sequences[i];
40
+ var clipCount = 0;
41
+ for (var t = 0; t < seq.videoTracks.numTracks; t++) clipCount += seq.videoTracks[t].clips.numItems;
42
+ for (var t = 0; t < seq.audioTracks.numTracks; t++) clipCount += seq.audioTracks[t].clips.numItems;
43
+ sequences.push({
44
+ name: seq.name,
45
+ id: seq.sequenceID,
46
+ width: seq.frameSizeHorizontal,
47
+ height: seq.frameSizeVertical,
48
+ durationSeconds: __ticksToSeconds(seq.end),
49
+ videoTracks: seq.videoTracks.numTracks,
50
+ audioTracks: seq.audioTracks.numTracks,
51
+ totalClips: clipCount
52
+ });
53
+ }
54
+
55
+ var totalItems = 0;
56
+ var offlineCount = 0;
57
+ var mediaTypes = {};
58
+ function countItems(bin) {
59
+ for (var i = 0; i < bin.children.numItems; i++) {
60
+ var item = bin.children[i];
61
+ totalItems++;
62
+ try { if (item.isOffline()) offlineCount++; } catch(e) {}
63
+ try {
64
+ var mp = item.getMediaPath();
65
+ if (mp) {
66
+ var ext = mp.split(".").pop().toLowerCase();
67
+ if (!mediaTypes[ext]) mediaTypes[ext] = 0;
68
+ mediaTypes[ext]++;
69
+ }
70
+ } catch(e) {}
71
+ if (item.type === 2) countItems(item);
72
+ }
73
+ }
74
+ countItems(project.rootItem);
75
+
76
+ var activeSeqInfo = null;
77
+ var active = project.activeSequence;
78
+ if (active) {
79
+ activeSeqInfo = { name: active.name, id: active.sequenceID };
80
+ }
81
+
82
+ return __result({
83
+ projectName: project.name,
84
+ projectPath: project.path,
85
+ totalItems: totalItems,
86
+ offlineItems: offlineCount,
87
+ sequenceCount: sequences.length,
88
+ mediaFileTypes: mediaTypes,
89
+ activeSequence: activeSeqInfo,
90
+ sequences: sequences,
91
+ binTree: binTree
92
+ });
93
93
  `);
94
94
  return sendCommand(script, bridgeOptions);
95
95
  },
@@ -112,107 +112,107 @@ export function getInspectionTools(bridgeOptions) {
112
112
  },
113
113
  handler: async (args) => {
114
114
  const recursive = args.recursive !== false;
115
- const script = buildToolScript(`
116
- var root = app.project.rootItem;
117
- var target = null;
118
-
119
- // Try by node ID first
120
- function findById(parent, id) {
121
- for (var i = 0; i < parent.children.numItems; i++) {
122
- var item = parent.children[i];
123
- if (item.nodeId === id) return item;
124
- if (item.type === 2) {
125
- var found = findById(item, id);
126
- if (found) return found;
127
- }
128
- }
129
- return null;
130
- }
131
-
132
- target = findById(root, "${escapeForExtendScript(args.bin_id)}");
133
-
134
- // Try by path
135
- if (!target) {
136
- var parts = "${escapeForExtendScript(args.bin_id)}".split("/");
137
- var current = root;
138
- for (var p = 0; p < parts.length; p++) {
139
- var found = false;
140
- for (var i = 0; i < current.children.numItems; i++) {
141
- if (current.children[i].name === parts[p] && current.children[i].type === 2) {
142
- current = current.children[i];
143
- found = true;
144
- break;
145
- }
146
- }
147
- if (!found) { current = null; break; }
148
- }
149
- if (current && current !== root) target = current;
150
- }
151
-
152
- // Try by name
153
- if (!target) {
154
- function findByName(parent, name) {
155
- for (var i = 0; i < parent.children.numItems; i++) {
156
- var item = parent.children[i];
157
- if (item.name === name && item.type === 2) return item;
158
- if (item.type === 2) {
159
- var found = findByName(item, name);
160
- if (found) return found;
161
- }
162
- }
163
- return null;
164
- }
165
- target = findByName(root, "${escapeForExtendScript(args.bin_id)}");
166
- }
167
-
168
- if (!target) return __error("Bin not found: ${escapeForExtendScript(args.bin_id)}");
169
-
170
- function getItemDetails(item) {
171
- var info = {
172
- nodeId: item.nodeId,
173
- name: item.name,
174
- type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 4 ? "file" : "unknown",
175
- treePath: item.treePath
176
- };
177
- try { info.mediaPath = item.getMediaPath(); } catch(e) {}
178
- try { info.offline = item.isOffline(); } catch(e) {}
179
- try { info.colorLabel = item.getColorLabel(); } catch(e) {}
180
- try {
181
- var interp = item.getFootageInterpretation();
182
- if (interp) {
183
- info.frameRate = interp.frameRate;
184
- info.pixelAspectRatio = interp.pixelAspectRatio;
185
- }
186
- } catch(e) {}
187
- try {
188
- info.inPoint = __ticksToSeconds(item.getInPoint().ticks);
189
- info.outPoint = __ticksToSeconds(item.getOutPoint().ticks);
190
- } catch(e) {}
191
- return info;
192
- }
193
-
194
- function walkItems(bin, recurse) {
195
- var items = [];
196
- for (var i = 0; i < bin.children.numItems; i++) {
197
- var item = bin.children[i];
198
- var info = getItemDetails(item);
199
- if (item.type === 2 && recurse) {
200
- info.children = walkItems(item, true);
201
- info.childCount = info.children.length;
202
- }
203
- items.push(info);
204
- }
205
- return items;
206
- }
207
-
208
- var contents = walkItems(target, ${recursive});
209
- return __result({
210
- binName: target.name,
211
- binNodeId: target.nodeId,
212
- binPath: target.treePath,
213
- itemCount: contents.length,
214
- items: contents
215
- });
115
+ const script = buildToolScript(`
116
+ var root = app.project.rootItem;
117
+ var target = null;
118
+
119
+ // Try by node ID first
120
+ function findById(parent, id) {
121
+ for (var i = 0; i < parent.children.numItems; i++) {
122
+ var item = parent.children[i];
123
+ if (item.nodeId === id) return item;
124
+ if (item.type === 2) {
125
+ var found = findById(item, id);
126
+ if (found) return found;
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+
132
+ target = findById(root, "${escapeForExtendScript(args.bin_id)}");
133
+
134
+ // Try by path
135
+ if (!target) {
136
+ var parts = "${escapeForExtendScript(args.bin_id)}".split("/");
137
+ var current = root;
138
+ for (var p = 0; p < parts.length; p++) {
139
+ var found = false;
140
+ for (var i = 0; i < current.children.numItems; i++) {
141
+ if (current.children[i].name === parts[p] && current.children[i].type === 2) {
142
+ current = current.children[i];
143
+ found = true;
144
+ break;
145
+ }
146
+ }
147
+ if (!found) { current = null; break; }
148
+ }
149
+ if (current && current !== root) target = current;
150
+ }
151
+
152
+ // Try by name
153
+ if (!target) {
154
+ function findByName(parent, name) {
155
+ for (var i = 0; i < parent.children.numItems; i++) {
156
+ var item = parent.children[i];
157
+ if (item.name === name && item.type === 2) return item;
158
+ if (item.type === 2) {
159
+ var found = findByName(item, name);
160
+ if (found) return found;
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ target = findByName(root, "${escapeForExtendScript(args.bin_id)}");
166
+ }
167
+
168
+ if (!target) return __error("Bin not found: ${escapeForExtendScript(args.bin_id)}");
169
+
170
+ function getItemDetails(item) {
171
+ var info = {
172
+ nodeId: item.nodeId,
173
+ name: item.name,
174
+ type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 4 ? "file" : "unknown",
175
+ treePath: item.treePath
176
+ };
177
+ try { info.mediaPath = item.getMediaPath(); } catch(e) {}
178
+ try { info.offline = item.isOffline(); } catch(e) {}
179
+ try { info.colorLabel = item.getColorLabel(); } catch(e) {}
180
+ try {
181
+ var interp = item.getFootageInterpretation();
182
+ if (interp) {
183
+ info.frameRate = interp.frameRate;
184
+ info.pixelAspectRatio = interp.pixelAspectRatio;
185
+ }
186
+ } catch(e) {}
187
+ try {
188
+ info.inPoint = __ticksToSeconds(item.getInPoint().ticks);
189
+ info.outPoint = __ticksToSeconds(item.getOutPoint().ticks);
190
+ } catch(e) {}
191
+ return info;
192
+ }
193
+
194
+ function walkItems(bin, recurse) {
195
+ var items = [];
196
+ for (var i = 0; i < bin.children.numItems; i++) {
197
+ var item = bin.children[i];
198
+ var info = getItemDetails(item);
199
+ if (item.type === 2 && recurse) {
200
+ info.children = walkItems(item, true);
201
+ info.childCount = info.children.length;
202
+ }
203
+ items.push(info);
204
+ }
205
+ return items;
206
+ }
207
+
208
+ var contents = walkItems(target, ${recursive});
209
+ return __result({
210
+ binName: target.name,
211
+ binNodeId: target.nodeId,
212
+ binPath: target.treePath,
213
+ itemCount: contents.length,
214
+ items: contents
215
+ });
216
216
  `);
217
217
  return sendCommand(script, bridgeOptions);
218
218
  },
@@ -232,205 +232,205 @@ export function getInspectionTools(bridgeOptions) {
232
232
  const seqLookup = args.sequence_id
233
233
  ? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
234
234
  : `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
235
- const script = buildToolScript(`
236
- ${seqLookup}
237
-
238
- // Settings
239
- var info = {
240
- name: seq.name,
241
- id: seq.sequenceID,
242
- width: seq.frameSizeHorizontal,
243
- height: seq.frameSizeVertical,
244
- durationSeconds: __ticksToSeconds(seq.end)
245
- };
246
-
247
- try {
248
- var s = seq.getSettings();
249
- if (s) {
250
- info.frameRate = s.videoFrameRate;
251
- info.audioSampleRate = s.audioSampleRate;
252
- info.audioChannelType = s.audioChannelType;
253
- info.audioChannelCount = s.audioChannelCount;
254
- info.videoFieldType = s.videoFieldType;
255
- info.videoDisplayFormat = s.videoDisplayFormat;
256
- info.audioDisplayFormat = s.audioDisplayFormat;
257
- }
258
- } catch(e) {}
259
-
260
- // Playhead
261
- try { info.playheadSeconds = __ticksToSeconds(seq.getPlayerPosition().ticks); } catch(e) {}
262
-
263
- // In/Out points
264
- try { info.inPointSeconds = __ticksToSeconds(seq.getInPoint()); } catch(e) {}
265
- try { info.outPointSeconds = __ticksToSeconds(seq.getOutPoint()); } catch(e) {}
266
-
267
- // Work area
268
- try { info.workAreaIn = __ticksToSeconds(seq.getWorkAreaInPoint()); } catch(e) {}
269
- try { info.workAreaOut = __ticksToSeconds(seq.getWorkAreaOutPoint()); } catch(e) {}
270
-
271
- // Zero point
272
- try { info.zeroPoint = __ticksToSeconds(seq.zeroPoint); } catch(e) {}
273
-
274
- // Markers
275
- var markers = [];
276
- try {
277
- var m = seq.markers.getFirstMarker();
278
- while (m) {
279
- var mInfo = {
280
- name: m.name,
281
- comments: m.comments,
282
- startSeconds: __ticksToSeconds(m.start.ticks),
283
- endSeconds: __ticksToSeconds(m.end.ticks),
284
- type: m.type
285
- };
286
- try { mInfo.colorIndex = m.getColorByIndex(); } catch(e) {}
287
- markers.push(mInfo);
288
- m = seq.markers.getNextMarker(m);
289
- }
290
- } catch(e) {}
291
- info.markers = markers;
292
- info.markerCount = markers.length;
293
-
294
- // Video tracks
295
- info.videoTracks = [];
296
- for (var t = 0; t < seq.videoTracks.numTracks; t++) {
297
- var track = seq.videoTracks[t];
298
- var trackInfo = {
299
- index: t,
300
- name: track.name,
301
- isMuted: track.isMuted(),
302
- isLocked: track.isLocked()
303
- };
304
- try { trackInfo.isTargeted = track.isTargeted(); } catch(e) {}
305
-
306
- // Clips
307
- trackInfo.clips = [];
308
- for (var c = 0; c < track.clips.numItems; c++) {
309
- var clip = track.clips[c];
310
- var ci = {
311
- index: c,
312
- nodeId: clip.nodeId,
313
- name: clip.name,
314
- startSeconds: __ticksToSeconds(clip.start.ticks),
315
- endSeconds: __ticksToSeconds(clip.end.ticks),
316
- durationSeconds: __ticksToSeconds(clip.duration.ticks),
317
- inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
318
- outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
319
- mediaType: clip.mediaType
320
- };
321
- try { ci.enabled = !clip.isDisabled(); } catch(e) { ci.enabled = true; }
322
- try { ci.speed = clip.getSpeed(); } catch(e) {}
323
- try { ci.reversed = clip.isSpeedReversed(); } catch(e) {}
324
- try { ci.isAdjustmentLayer = clip.isAdjustmentLayer(); } catch(e) {}
325
- try { ci.isSelected = clip.isSelected(); } catch(e) {}
326
-
327
- // Source media info
328
- try {
329
- if (clip.projectItem) {
330
- ci.sourceNodeId = clip.projectItem.nodeId;
331
- ci.sourceName = clip.projectItem.name;
332
- try { ci.sourceMediaPath = clip.projectItem.getMediaPath(); } catch(e) {}
333
- try { ci.sourceOffline = clip.projectItem.isOffline(); } catch(e) {}
334
- }
335
- } catch(e) {}
336
-
337
- // Effect count
338
- try {
339
- ci.effectCount = clip.components.numItems;
340
- ci.effects = [];
341
- for (var e = 0; e < clip.components.numItems; e++) {
342
- ci.effects.push(clip.components[e].displayName);
343
- }
344
- } catch(e) {}
345
-
346
- trackInfo.clips.push(ci);
347
- }
348
-
349
- // Transitions
350
- trackInfo.transitions = [];
351
- try {
352
- for (var tr = 0; tr < track.transitions.numItems; tr++) {
353
- var trans = track.transitions[tr];
354
- trackInfo.transitions.push({
355
- index: tr,
356
- startSeconds: __ticksToSeconds(trans.start.ticks),
357
- endSeconds: __ticksToSeconds(trans.end.ticks),
358
- type: trans.type
359
- });
360
- }
361
- } catch(e) {}
362
-
363
- trackInfo.clipCount = trackInfo.clips.length;
364
- trackInfo.transitionCount = trackInfo.transitions.length;
365
- info.videoTracks.push(trackInfo);
366
- }
367
-
368
- // Audio tracks
369
- info.audioTracks = [];
370
- for (var t = 0; t < seq.audioTracks.numTracks; t++) {
371
- var track = seq.audioTracks[t];
372
- var trackInfo = {
373
- index: t,
374
- name: track.name,
375
- isMuted: track.isMuted(),
376
- isLocked: track.isLocked()
377
- };
378
- try { trackInfo.isTargeted = track.isTargeted(); } catch(e) {}
379
-
380
- trackInfo.clips = [];
381
- for (var c = 0; c < track.clips.numItems; c++) {
382
- var clip = track.clips[c];
383
- var ci = {
384
- index: c,
385
- nodeId: clip.nodeId,
386
- name: clip.name,
387
- startSeconds: __ticksToSeconds(clip.start.ticks),
388
- endSeconds: __ticksToSeconds(clip.end.ticks),
389
- durationSeconds: __ticksToSeconds(clip.duration.ticks),
390
- inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
391
- outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
392
- mediaType: clip.mediaType
393
- };
394
- try { ci.enabled = !clip.isDisabled(); } catch(e) { ci.enabled = true; }
395
- try { ci.speed = clip.getSpeed(); } catch(e) {}
396
- try {
397
- if (clip.projectItem) {
398
- ci.sourceNodeId = clip.projectItem.nodeId;
399
- ci.sourceName = clip.projectItem.name;
400
- try { ci.sourceMediaPath = clip.projectItem.getMediaPath(); } catch(e) {}
401
- }
402
- } catch(e) {}
403
- try {
404
- ci.effectCount = clip.components.numItems;
405
- ci.effects = [];
406
- for (var e = 0; e < clip.components.numItems; e++) {
407
- ci.effects.push(clip.components[e].displayName);
408
- }
409
- } catch(e) {}
410
- trackInfo.clips.push(ci);
411
- }
412
-
413
- trackInfo.transitions = [];
414
- try {
415
- for (var tr = 0; tr < track.transitions.numItems; tr++) {
416
- var trans = track.transitions[tr];
417
- trackInfo.transitions.push({
418
- index: tr,
419
- startSeconds: __ticksToSeconds(trans.start.ticks),
420
- endSeconds: __ticksToSeconds(trans.end.ticks)
421
- });
422
- }
423
- } catch(e) {}
424
-
425
- trackInfo.clipCount = trackInfo.clips.length;
426
- trackInfo.transitionCount = trackInfo.transitions.length;
427
- info.audioTracks.push(trackInfo);
428
- }
429
-
430
- info.videoTrackCount = info.videoTracks.length;
431
- info.audioTrackCount = info.audioTracks.length;
432
-
433
- return __result(info);
235
+ const script = buildToolScript(`
236
+ ${seqLookup}
237
+
238
+ // Settings
239
+ var info = {
240
+ name: seq.name,
241
+ id: seq.sequenceID,
242
+ width: seq.frameSizeHorizontal,
243
+ height: seq.frameSizeVertical,
244
+ durationSeconds: __ticksToSeconds(seq.end)
245
+ };
246
+
247
+ try {
248
+ var s = seq.getSettings();
249
+ if (s) {
250
+ info.frameRate = s.videoFrameRate;
251
+ info.audioSampleRate = s.audioSampleRate;
252
+ info.audioChannelType = s.audioChannelType;
253
+ info.audioChannelCount = s.audioChannelCount;
254
+ info.videoFieldType = s.videoFieldType;
255
+ info.videoDisplayFormat = s.videoDisplayFormat;
256
+ info.audioDisplayFormat = s.audioDisplayFormat;
257
+ }
258
+ } catch(e) {}
259
+
260
+ // Playhead
261
+ try { info.playheadSeconds = __ticksToSeconds(seq.getPlayerPosition().ticks); } catch(e) {}
262
+
263
+ // In/Out points
264
+ try { info.inPointSeconds = __ticksToSeconds(seq.getInPoint()); } catch(e) {}
265
+ try { info.outPointSeconds = __ticksToSeconds(seq.getOutPoint()); } catch(e) {}
266
+
267
+ // Work area
268
+ try { info.workAreaIn = __ticksToSeconds(seq.getWorkAreaInPoint()); } catch(e) {}
269
+ try { info.workAreaOut = __ticksToSeconds(seq.getWorkAreaOutPoint()); } catch(e) {}
270
+
271
+ // Zero point
272
+ try { info.zeroPoint = __ticksToSeconds(seq.zeroPoint); } catch(e) {}
273
+
274
+ // Markers
275
+ var markers = [];
276
+ try {
277
+ var m = seq.markers.getFirstMarker();
278
+ while (m) {
279
+ var mInfo = {
280
+ name: m.name,
281
+ comments: m.comments,
282
+ startSeconds: __ticksToSeconds(m.start.ticks),
283
+ endSeconds: __ticksToSeconds(m.end.ticks),
284
+ type: m.type
285
+ };
286
+ try { mInfo.colorIndex = m.getColorByIndex(); } catch(e) {}
287
+ markers.push(mInfo);
288
+ m = seq.markers.getNextMarker(m);
289
+ }
290
+ } catch(e) {}
291
+ info.markers = markers;
292
+ info.markerCount = markers.length;
293
+
294
+ // Video tracks
295
+ info.videoTracks = [];
296
+ for (var t = 0; t < seq.videoTracks.numTracks; t++) {
297
+ var track = seq.videoTracks[t];
298
+ var trackInfo = {
299
+ index: t,
300
+ name: track.name,
301
+ isMuted: track.isMuted(),
302
+ isLocked: track.isLocked()
303
+ };
304
+ try { trackInfo.isTargeted = track.isTargeted(); } catch(e) {}
305
+
306
+ // Clips
307
+ trackInfo.clips = [];
308
+ for (var c = 0; c < track.clips.numItems; c++) {
309
+ var clip = track.clips[c];
310
+ var ci = {
311
+ index: c,
312
+ nodeId: clip.nodeId,
313
+ name: clip.name,
314
+ startSeconds: __ticksToSeconds(clip.start.ticks),
315
+ endSeconds: __ticksToSeconds(clip.end.ticks),
316
+ durationSeconds: __ticksToSeconds(clip.duration.ticks),
317
+ inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
318
+ outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
319
+ mediaType: clip.mediaType
320
+ };
321
+ try { ci.enabled = !clip.isDisabled(); } catch(e) { ci.enabled = true; }
322
+ try { ci.speed = clip.getSpeed(); } catch(e) {}
323
+ try { ci.reversed = clip.isSpeedReversed(); } catch(e) {}
324
+ try { ci.isAdjustmentLayer = clip.isAdjustmentLayer(); } catch(e) {}
325
+ try { ci.isSelected = clip.isSelected(); } catch(e) {}
326
+
327
+ // Source media info
328
+ try {
329
+ if (clip.projectItem) {
330
+ ci.sourceNodeId = clip.projectItem.nodeId;
331
+ ci.sourceName = clip.projectItem.name;
332
+ try { ci.sourceMediaPath = clip.projectItem.getMediaPath(); } catch(e) {}
333
+ try { ci.sourceOffline = clip.projectItem.isOffline(); } catch(e) {}
334
+ }
335
+ } catch(e) {}
336
+
337
+ // Effect count
338
+ try {
339
+ ci.effectCount = clip.components.numItems;
340
+ ci.effects = [];
341
+ for (var e = 0; e < clip.components.numItems; e++) {
342
+ ci.effects.push(clip.components[e].displayName);
343
+ }
344
+ } catch(e) {}
345
+
346
+ trackInfo.clips.push(ci);
347
+ }
348
+
349
+ // Transitions
350
+ trackInfo.transitions = [];
351
+ try {
352
+ for (var tr = 0; tr < track.transitions.numItems; tr++) {
353
+ var trans = track.transitions[tr];
354
+ trackInfo.transitions.push({
355
+ index: tr,
356
+ startSeconds: __ticksToSeconds(trans.start.ticks),
357
+ endSeconds: __ticksToSeconds(trans.end.ticks),
358
+ type: trans.type
359
+ });
360
+ }
361
+ } catch(e) {}
362
+
363
+ trackInfo.clipCount = trackInfo.clips.length;
364
+ trackInfo.transitionCount = trackInfo.transitions.length;
365
+ info.videoTracks.push(trackInfo);
366
+ }
367
+
368
+ // Audio tracks
369
+ info.audioTracks = [];
370
+ for (var t = 0; t < seq.audioTracks.numTracks; t++) {
371
+ var track = seq.audioTracks[t];
372
+ var trackInfo = {
373
+ index: t,
374
+ name: track.name,
375
+ isMuted: track.isMuted(),
376
+ isLocked: track.isLocked()
377
+ };
378
+ try { trackInfo.isTargeted = track.isTargeted(); } catch(e) {}
379
+
380
+ trackInfo.clips = [];
381
+ for (var c = 0; c < track.clips.numItems; c++) {
382
+ var clip = track.clips[c];
383
+ var ci = {
384
+ index: c,
385
+ nodeId: clip.nodeId,
386
+ name: clip.name,
387
+ startSeconds: __ticksToSeconds(clip.start.ticks),
388
+ endSeconds: __ticksToSeconds(clip.end.ticks),
389
+ durationSeconds: __ticksToSeconds(clip.duration.ticks),
390
+ inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
391
+ outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
392
+ mediaType: clip.mediaType
393
+ };
394
+ try { ci.enabled = !clip.isDisabled(); } catch(e) { ci.enabled = true; }
395
+ try { ci.speed = clip.getSpeed(); } catch(e) {}
396
+ try {
397
+ if (clip.projectItem) {
398
+ ci.sourceNodeId = clip.projectItem.nodeId;
399
+ ci.sourceName = clip.projectItem.name;
400
+ try { ci.sourceMediaPath = clip.projectItem.getMediaPath(); } catch(e) {}
401
+ }
402
+ } catch(e) {}
403
+ try {
404
+ ci.effectCount = clip.components.numItems;
405
+ ci.effects = [];
406
+ for (var e = 0; e < clip.components.numItems; e++) {
407
+ ci.effects.push(clip.components[e].displayName);
408
+ }
409
+ } catch(e) {}
410
+ trackInfo.clips.push(ci);
411
+ }
412
+
413
+ trackInfo.transitions = [];
414
+ try {
415
+ for (var tr = 0; tr < track.transitions.numItems; tr++) {
416
+ var trans = track.transitions[tr];
417
+ trackInfo.transitions.push({
418
+ index: tr,
419
+ startSeconds: __ticksToSeconds(trans.start.ticks),
420
+ endSeconds: __ticksToSeconds(trans.end.ticks)
421
+ });
422
+ }
423
+ } catch(e) {}
424
+
425
+ trackInfo.clipCount = trackInfo.clips.length;
426
+ trackInfo.transitionCount = trackInfo.transitions.length;
427
+ info.audioTracks.push(trackInfo);
428
+ }
429
+
430
+ info.videoTrackCount = info.videoTracks.length;
431
+ info.audioTrackCount = info.audioTracks.length;
432
+
433
+ return __result(info);
434
434
  `);
435
435
  return sendCommand(script, bridgeOptions);
436
436
  },
@@ -448,120 +448,120 @@ export function getInspectionTools(bridgeOptions) {
448
448
  required: ["node_id"],
449
449
  },
450
450
  handler: async (args) => {
451
- const script = buildToolScript(`
452
- var found = __findClip("${escapeForExtendScript(args.node_id)}");
453
- if (!found) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
454
-
455
- var clip = found.clip;
456
- var info = {
457
- nodeId: clip.nodeId,
458
- name: clip.name,
459
- trackType: found.trackType,
460
- trackIndex: found.trackIndex,
461
- clipIndex: found.clipIndex,
462
- startSeconds: __ticksToSeconds(clip.start.ticks),
463
- endSeconds: __ticksToSeconds(clip.end.ticks),
464
- durationSeconds: __ticksToSeconds(clip.duration.ticks),
465
- inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
466
- outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
467
- mediaType: clip.mediaType
468
- };
469
-
470
- try { info.enabled = !clip.isDisabled(); } catch(e) { info.enabled = true; }
471
- try { info.speed = clip.getSpeed(); } catch(e) {}
472
- try { info.reversed = clip.isSpeedReversed(); } catch(e) {}
473
- try { info.isSelected = clip.isSelected(); } catch(e) {}
474
- try { info.isAdjustmentLayer = clip.isAdjustmentLayer(); } catch(e) {}
475
-
476
- // Source project item details
477
- try {
478
- var src = clip.projectItem;
479
- if (src) {
480
- info.source = {
481
- nodeId: src.nodeId,
482
- name: src.name,
483
- treePath: src.treePath
484
- };
485
- try { info.source.mediaPath = src.getMediaPath(); } catch(e) {}
486
- try { info.source.offline = src.isOffline(); } catch(e) {}
487
- try { info.source.colorLabel = src.getColorLabel(); } catch(e) {}
488
- try {
489
- var interp = src.getFootageInterpretation();
490
- if (interp) {
491
- info.source.frameRate = interp.frameRate;
492
- info.source.pixelAspectRatio = interp.pixelAspectRatio;
493
- info.source.fieldType = interp.fieldType;
494
- info.source.alphaUsage = interp.alphaUsage;
495
- }
496
- } catch(e) {}
497
- // XMP metadata
498
- try {
499
- var xmp = src.getProjectMetadata();
500
- if (xmp && xmp.length < 5000) info.source.projectMetadata = xmp;
501
- } catch(e) {}
502
- // Proxy info
503
- try { info.source.hasProxy = src.hasProxy(); } catch(e) {}
504
- try { info.source.canChangeMediaPath = src.canChangeMediaPath(); } catch(e) {}
505
- }
506
- } catch(e) {}
507
-
508
- // All effects/components with full property details
509
- info.components = [];
510
- try {
511
- for (var i = 0; i < clip.components.numItems; i++) {
512
- var comp = clip.components[i];
513
- var compInfo = {
514
- index: i,
515
- displayName: comp.displayName,
516
- matchName: comp.matchName,
517
- properties: []
518
- };
519
- for (var p = 0; p < comp.properties.numItems; p++) {
520
- var prop = comp.properties[p];
521
- var propInfo = {
522
- index: p,
523
- displayName: prop.displayName
524
- };
525
- try { propInfo.matchName = prop.matchName; } catch(e) {}
526
- try { propInfo.value = prop.getValue(0, 0); } catch(e) {}
527
- try { propInfo.isTimeVarying = prop.isTimeVarying(); } catch(e) {}
528
- try { propInfo.keyframesSupported = prop.areKeyframesSupported(); } catch(e) {}
529
- try {
530
- if (prop.isTimeVarying()) {
531
- var keys = prop.getKeys();
532
- if (keys && keys.length > 0) {
533
- propInfo.keyframeCount = keys.length;
534
- propInfo.keyframeTimes = [];
535
- for (var k = 0; k < Math.min(keys.length, 20); k++) {
536
- propInfo.keyframeTimes.push(__ticksToSeconds(keys[k].ticks));
537
- }
538
- if (keys.length > 20) propInfo.keyframesTruncated = true;
539
- }
540
- }
541
- } catch(e) {}
542
- compInfo.properties.push(propInfo);
543
- }
544
- info.components.push(compInfo);
545
- }
546
- } catch(e) {}
547
- info.componentCount = info.components.length;
548
-
549
- // Clip markers
550
- info.markers = [];
551
- try {
552
- var m = clip.markers.getFirstMarker();
553
- while (m) {
554
- info.markers.push({
555
- name: m.name,
556
- comments: m.comments,
557
- startSeconds: __ticksToSeconds(m.start.ticks),
558
- endSeconds: __ticksToSeconds(m.end.ticks)
559
- });
560
- m = clip.markers.getNextMarker(m);
561
- }
562
- } catch(e) {}
563
-
564
- return __result(info);
451
+ const script = buildToolScript(`
452
+ var found = __findClip("${escapeForExtendScript(args.node_id)}");
453
+ if (!found) return __error("Clip not found: ${escapeForExtendScript(args.node_id)}");
454
+
455
+ var clip = found.clip;
456
+ var info = {
457
+ nodeId: clip.nodeId,
458
+ name: clip.name,
459
+ trackType: found.trackType,
460
+ trackIndex: found.trackIndex,
461
+ clipIndex: found.clipIndex,
462
+ startSeconds: __ticksToSeconds(clip.start.ticks),
463
+ endSeconds: __ticksToSeconds(clip.end.ticks),
464
+ durationSeconds: __ticksToSeconds(clip.duration.ticks),
465
+ inPointSeconds: __ticksToSeconds(clip.inPoint.ticks),
466
+ outPointSeconds: __ticksToSeconds(clip.outPoint.ticks),
467
+ mediaType: clip.mediaType
468
+ };
469
+
470
+ try { info.enabled = !clip.isDisabled(); } catch(e) { info.enabled = true; }
471
+ try { info.speed = clip.getSpeed(); } catch(e) {}
472
+ try { info.reversed = clip.isSpeedReversed(); } catch(e) {}
473
+ try { info.isSelected = clip.isSelected(); } catch(e) {}
474
+ try { info.isAdjustmentLayer = clip.isAdjustmentLayer(); } catch(e) {}
475
+
476
+ // Source project item details
477
+ try {
478
+ var src = clip.projectItem;
479
+ if (src) {
480
+ info.source = {
481
+ nodeId: src.nodeId,
482
+ name: src.name,
483
+ treePath: src.treePath
484
+ };
485
+ try { info.source.mediaPath = src.getMediaPath(); } catch(e) {}
486
+ try { info.source.offline = src.isOffline(); } catch(e) {}
487
+ try { info.source.colorLabel = src.getColorLabel(); } catch(e) {}
488
+ try {
489
+ var interp = src.getFootageInterpretation();
490
+ if (interp) {
491
+ info.source.frameRate = interp.frameRate;
492
+ info.source.pixelAspectRatio = interp.pixelAspectRatio;
493
+ info.source.fieldType = interp.fieldType;
494
+ info.source.alphaUsage = interp.alphaUsage;
495
+ }
496
+ } catch(e) {}
497
+ // XMP metadata
498
+ try {
499
+ var xmp = src.getProjectMetadata();
500
+ if (xmp && xmp.length < 5000) info.source.projectMetadata = xmp;
501
+ } catch(e) {}
502
+ // Proxy info
503
+ try { info.source.hasProxy = src.hasProxy(); } catch(e) {}
504
+ try { info.source.canChangeMediaPath = src.canChangeMediaPath(); } catch(e) {}
505
+ }
506
+ } catch(e) {}
507
+
508
+ // All effects/components with full property details
509
+ info.components = [];
510
+ try {
511
+ for (var i = 0; i < clip.components.numItems; i++) {
512
+ var comp = clip.components[i];
513
+ var compInfo = {
514
+ index: i,
515
+ displayName: comp.displayName,
516
+ matchName: comp.matchName,
517
+ properties: []
518
+ };
519
+ for (var p = 0; p < comp.properties.numItems; p++) {
520
+ var prop = comp.properties[p];
521
+ var propInfo = {
522
+ index: p,
523
+ displayName: prop.displayName
524
+ };
525
+ try { propInfo.matchName = prop.matchName; } catch(e) {}
526
+ try { propInfo.value = prop.getValue(0, 0); } catch(e) {}
527
+ try { propInfo.isTimeVarying = prop.isTimeVarying(); } catch(e) {}
528
+ try { propInfo.keyframesSupported = prop.areKeyframesSupported(); } catch(e) {}
529
+ try {
530
+ if (prop.isTimeVarying()) {
531
+ var keys = prop.getKeys();
532
+ if (keys && keys.length > 0) {
533
+ propInfo.keyframeCount = keys.length;
534
+ propInfo.keyframeTimes = [];
535
+ for (var k = 0; k < Math.min(keys.length, 20); k++) {
536
+ propInfo.keyframeTimes.push(__ticksToSeconds(keys[k].ticks));
537
+ }
538
+ if (keys.length > 20) propInfo.keyframesTruncated = true;
539
+ }
540
+ }
541
+ } catch(e) {}
542
+ compInfo.properties.push(propInfo);
543
+ }
544
+ info.components.push(compInfo);
545
+ }
546
+ } catch(e) {}
547
+ info.componentCount = info.components.length;
548
+
549
+ // Clip markers
550
+ info.markers = [];
551
+ try {
552
+ var m = clip.markers.getFirstMarker();
553
+ while (m) {
554
+ info.markers.push({
555
+ name: m.name,
556
+ comments: m.comments,
557
+ startSeconds: __ticksToSeconds(m.start.ticks),
558
+ endSeconds: __ticksToSeconds(m.end.ticks)
559
+ });
560
+ m = clip.markers.getNextMarker(m);
561
+ }
562
+ } catch(e) {}
563
+
564
+ return __result(info);
565
565
  `);
566
566
  return sendCommand(script, bridgeOptions);
567
567
  },
@@ -579,79 +579,79 @@ export function getInspectionTools(bridgeOptions) {
579
579
  required: ["item_id"],
580
580
  },
581
581
  handler: async (args) => {
582
- const script = buildToolScript(`
583
- var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
584
- if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
585
-
586
- var info = {
587
- nodeId: item.nodeId,
588
- name: item.name,
589
- type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 3 ? "root" : item.type === 4 ? "file" : "unknown",
590
- treePath: item.treePath
591
- };
592
-
593
- try { info.mediaPath = item.getMediaPath(); } catch(e) {}
594
- try { info.offline = item.isOffline(); } catch(e) {}
595
- try { info.colorLabel = item.getColorLabel(); } catch(e) {}
596
- try { info.canChangeMediaPath = item.canChangeMediaPath(); } catch(e) {}
597
-
598
- // Footage interpretation
599
- try {
600
- var interp = item.getFootageInterpretation();
601
- if (interp) {
602
- info.frameRate = interp.frameRate;
603
- info.pixelAspectRatio = interp.pixelAspectRatio;
604
- info.fieldType = interp.fieldType;
605
- info.alphaUsage = interp.alphaUsage;
606
- info.ignoreAlpha = interp.ignoreAlpha;
607
- info.invertAlpha = interp.invertAlpha;
608
- }
609
- } catch(e) {}
610
-
611
- // In/Out points
612
- try { info.inPoint = __ticksToSeconds(item.getInPoint().ticks); } catch(e) {}
613
- try { info.outPoint = __ticksToSeconds(item.getOutPoint().ticks); } catch(e) {}
614
-
615
- // Proxy
616
- try { info.hasProxy = item.hasProxy(); } catch(e) {}
617
-
618
- // Project metadata (XMP)
619
- try {
620
- var xmp = item.getProjectMetadata();
621
- if (xmp && xmp.length < 10000) info.projectMetadata = xmp;
622
- else if (xmp) info.projectMetadataLength = xmp.length;
623
- } catch(e) {}
624
-
625
- // XMP metadata
626
- try {
627
- var xmp2 = item.getXMPMetadata();
628
- if (xmp2 && xmp2.length < 10000) info.xmpMetadata = xmp2;
629
- else if (xmp2) info.xmpMetadataLength = xmp2.length;
630
- } catch(e) {}
631
-
632
- // Item markers
633
- info.markers = [];
634
- try {
635
- var m = item.getMarkers();
636
- if (m) {
637
- var marker = m.getFirstMarker();
638
- while (marker) {
639
- info.markers.push({
640
- name: marker.name,
641
- comments: marker.comments,
642
- startSeconds: __ticksToSeconds(marker.start.ticks)
643
- });
644
- marker = m.getNextMarker(marker);
645
- }
646
- }
647
- } catch(e) {}
648
-
649
- // Child count for bins
650
- if (item.type === 2) {
651
- info.childCount = item.children.numItems;
652
- }
653
-
654
- return __result(info);
582
+ const script = buildToolScript(`
583
+ var item = __findProjectItem("${escapeForExtendScript(args.item_id)}");
584
+ if (!item) return __error("Item not found: ${escapeForExtendScript(args.item_id)}");
585
+
586
+ var info = {
587
+ nodeId: item.nodeId,
588
+ name: item.name,
589
+ type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 3 ? "root" : item.type === 4 ? "file" : "unknown",
590
+ treePath: item.treePath
591
+ };
592
+
593
+ try { info.mediaPath = item.getMediaPath(); } catch(e) {}
594
+ try { info.offline = item.isOffline(); } catch(e) {}
595
+ try { info.colorLabel = item.getColorLabel(); } catch(e) {}
596
+ try { info.canChangeMediaPath = item.canChangeMediaPath(); } catch(e) {}
597
+
598
+ // Footage interpretation
599
+ try {
600
+ var interp = item.getFootageInterpretation();
601
+ if (interp) {
602
+ info.frameRate = interp.frameRate;
603
+ info.pixelAspectRatio = interp.pixelAspectRatio;
604
+ info.fieldType = interp.fieldType;
605
+ info.alphaUsage = interp.alphaUsage;
606
+ info.ignoreAlpha = interp.ignoreAlpha;
607
+ info.invertAlpha = interp.invertAlpha;
608
+ }
609
+ } catch(e) {}
610
+
611
+ // In/Out points
612
+ try { info.inPoint = __ticksToSeconds(item.getInPoint().ticks); } catch(e) {}
613
+ try { info.outPoint = __ticksToSeconds(item.getOutPoint().ticks); } catch(e) {}
614
+
615
+ // Proxy
616
+ try { info.hasProxy = item.hasProxy(); } catch(e) {}
617
+
618
+ // Project metadata (XMP)
619
+ try {
620
+ var xmp = item.getProjectMetadata();
621
+ if (xmp && xmp.length < 10000) info.projectMetadata = xmp;
622
+ else if (xmp) info.projectMetadataLength = xmp.length;
623
+ } catch(e) {}
624
+
625
+ // XMP metadata
626
+ try {
627
+ var xmp2 = item.getXMPMetadata();
628
+ if (xmp2 && xmp2.length < 10000) info.xmpMetadata = xmp2;
629
+ else if (xmp2) info.xmpMetadataLength = xmp2.length;
630
+ } catch(e) {}
631
+
632
+ // Item markers
633
+ info.markers = [];
634
+ try {
635
+ var m = item.getMarkers();
636
+ if (m) {
637
+ var marker = m.getFirstMarker();
638
+ while (marker) {
639
+ info.markers.push({
640
+ name: marker.name,
641
+ comments: marker.comments,
642
+ startSeconds: __ticksToSeconds(marker.start.ticks)
643
+ });
644
+ marker = m.getNextMarker(marker);
645
+ }
646
+ }
647
+ } catch(e) {}
648
+
649
+ // Child count for bins
650
+ if (item.type === 2) {
651
+ info.childCount = item.children.numItems;
652
+ }
653
+
654
+ return __result(info);
655
655
  `);
656
656
  return sendCommand(script, bridgeOptions);
657
657
  },
@@ -690,70 +690,70 @@ export function getInspectionTools(bridgeOptions) {
690
690
  },
691
691
  handler: async (args) => {
692
692
  const maxResults = args.max_results ?? 100;
693
- const script = buildToolScript(`
694
- var results = [];
695
- var maxR = ${maxResults};
696
- var query = ${args.query ? `"${escapeForExtendScript(args.query)}".toLowerCase()` : "null"};
697
- var ext = ${args.extension ? `"${escapeForExtendScript(args.extension)}".toLowerCase()` : "null"};
698
- var offlineOnly = ${args.offline_only ? "true" : "false"};
699
- var colorFilter = ${args.color_label !== undefined ? args.color_label : "-1"};
700
- var typeFilter = "${args.item_type || "all"}";
701
-
702
- function searchBin(bin) {
703
- if (results.length >= maxR) return;
704
- for (var i = 0; i < bin.children.numItems; i++) {
705
- if (results.length >= maxR) return;
706
- var item = bin.children[i];
707
-
708
- // Type filter
709
- if (typeFilter === "clip" && item.type === 2) {
710
- searchBin(item);
711
- continue;
712
- }
713
- if (typeFilter === "bin" && item.type !== 2) continue;
714
-
715
- var match = true;
716
-
717
- // Name filter
718
- if (query && item.name.toLowerCase().indexOf(query) === -1) match = false;
719
-
720
- // Extension filter
721
- if (match && ext) {
722
- try {
723
- var mp = item.getMediaPath();
724
- if (!mp || mp.split(".").pop().toLowerCase() !== ext) match = false;
725
- } catch(e) { match = false; }
726
- }
727
-
728
- // Offline filter
729
- if (match && offlineOnly) {
730
- try { if (!item.isOffline()) match = false; } catch(e) { match = false; }
731
- }
732
-
733
- // Color label filter
734
- if (match && colorFilter >= 0) {
735
- try { if (item.getColorLabel() !== colorFilter) match = false; } catch(e) { match = false; }
736
- }
737
-
738
- if (match) {
739
- var entry = {
740
- nodeId: item.nodeId,
741
- name: item.name,
742
- type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 4 ? "file" : "unknown",
743
- treePath: item.treePath
744
- };
745
- try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
746
- try { entry.offline = item.isOffline(); } catch(e) {}
747
- try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
748
- results.push(entry);
749
- }
750
-
751
- if (item.type === 2) searchBin(item);
752
- }
753
- }
754
-
755
- searchBin(app.project.rootItem);
756
- return __result({ resultCount: results.length, maxResults: maxR, items: results });
693
+ const script = buildToolScript(`
694
+ var results = [];
695
+ var maxR = ${maxResults};
696
+ var query = ${args.query ? `"${escapeForExtendScript(args.query)}".toLowerCase()` : "null"};
697
+ var ext = ${args.extension ? `"${escapeForExtendScript(args.extension)}".toLowerCase()` : "null"};
698
+ var offlineOnly = ${args.offline_only ? "true" : "false"};
699
+ var colorFilter = ${args.color_label !== undefined ? args.color_label : "-1"};
700
+ var typeFilter = "${args.item_type || "all"}";
701
+
702
+ function searchBin(bin) {
703
+ if (results.length >= maxR) return;
704
+ for (var i = 0; i < bin.children.numItems; i++) {
705
+ if (results.length >= maxR) return;
706
+ var item = bin.children[i];
707
+
708
+ // Type filter
709
+ if (typeFilter === "clip" && item.type === 2) {
710
+ searchBin(item);
711
+ continue;
712
+ }
713
+ if (typeFilter === "bin" && item.type !== 2) continue;
714
+
715
+ var match = true;
716
+
717
+ // Name filter
718
+ if (query && item.name.toLowerCase().indexOf(query) === -1) match = false;
719
+
720
+ // Extension filter
721
+ if (match && ext) {
722
+ try {
723
+ var mp = item.getMediaPath();
724
+ if (!mp || mp.split(".").pop().toLowerCase() !== ext) match = false;
725
+ } catch(e) { match = false; }
726
+ }
727
+
728
+ // Offline filter
729
+ if (match && offlineOnly) {
730
+ try { if (!item.isOffline()) match = false; } catch(e) { match = false; }
731
+ }
732
+
733
+ // Color label filter
734
+ if (match && colorFilter >= 0) {
735
+ try { if (item.getColorLabel() !== colorFilter) match = false; } catch(e) { match = false; }
736
+ }
737
+
738
+ if (match) {
739
+ var entry = {
740
+ nodeId: item.nodeId,
741
+ name: item.name,
742
+ type: item.type === 1 ? "clip" : item.type === 2 ? "bin" : item.type === 4 ? "file" : "unknown",
743
+ treePath: item.treePath
744
+ };
745
+ try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
746
+ try { entry.offline = item.isOffline(); } catch(e) {}
747
+ try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
748
+ results.push(entry);
749
+ }
750
+
751
+ if (item.type === 2) searchBin(item);
752
+ }
753
+ }
754
+
755
+ searchBin(app.project.rootItem);
756
+ return __result({ resultCount: results.length, maxResults: maxR, items: results });
757
757
  `);
758
758
  return sendCommand(script, bridgeOptions);
759
759
  },
@@ -784,48 +784,48 @@ export function getInspectionTools(bridgeOptions) {
784
784
  : `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
785
785
  const minGap = args.min_gap_seconds ?? 0.04;
786
786
  const trackType = args.track_type || "both";
787
- const script = buildToolScript(`
788
- ${seqLookup}
789
-
790
- var gaps = [];
791
- var minGapTicks = __secondsToTicks(${minGap});
792
-
793
- function findGaps(tracks, type) {
794
- for (var t = 0; t < tracks.numTracks; t++) {
795
- var track = tracks[t];
796
- if (track.clips.numItems === 0) continue;
797
- var prevEnd = 0;
798
- for (var c = 0; c < track.clips.numItems; c++) {
799
- var clip = track.clips[c];
800
- var startTicks = parseFloat(clip.start.ticks);
801
- var endTicks = parseFloat(clip.end.ticks);
802
- var gapTicks = startTicks - prevEnd;
803
- if (gapTicks > minGapTicks) {
804
- gaps.push({
805
- trackType: type,
806
- trackIndex: t,
807
- trackName: track.name,
808
- gapStartSeconds: __ticksToSeconds("" + prevEnd),
809
- gapEndSeconds: __ticksToSeconds("" + startTicks),
810
- gapDurationSeconds: __ticksToSeconds("" + gapTicks),
811
- beforeClip: c > 0 ? track.clips[c - 1].name : null,
812
- afterClip: clip.name
813
- });
814
- }
815
- prevEnd = endTicks;
816
- }
817
- }
818
- }
819
-
820
- if ("${trackType}" !== "audio") findGaps(seq.videoTracks, "video");
821
- if ("${trackType}" !== "video") findGaps(seq.audioTracks, "audio");
822
-
823
- return __result({
824
- sequenceName: seq.name,
825
- gapCount: gaps.length,
826
- minGapSeconds: ${minGap},
827
- gaps: gaps
828
- });
787
+ const script = buildToolScript(`
788
+ ${seqLookup}
789
+
790
+ var gaps = [];
791
+ var minGapTicks = __secondsToTicks(${minGap});
792
+
793
+ function findGaps(tracks, type) {
794
+ for (var t = 0; t < tracks.numTracks; t++) {
795
+ var track = tracks[t];
796
+ if (track.clips.numItems === 0) continue;
797
+ var prevEnd = 0;
798
+ for (var c = 0; c < track.clips.numItems; c++) {
799
+ var clip = track.clips[c];
800
+ var startTicks = parseFloat(clip.start.ticks);
801
+ var endTicks = parseFloat(clip.end.ticks);
802
+ var gapTicks = startTicks - prevEnd;
803
+ if (gapTicks > minGapTicks) {
804
+ gaps.push({
805
+ trackType: type,
806
+ trackIndex: t,
807
+ trackName: track.name,
808
+ gapStartSeconds: __ticksToSeconds("" + prevEnd),
809
+ gapEndSeconds: __ticksToSeconds("" + startTicks),
810
+ gapDurationSeconds: __ticksToSeconds("" + gapTicks),
811
+ beforeClip: c > 0 ? track.clips[c - 1].name : null,
812
+ afterClip: clip.name
813
+ });
814
+ }
815
+ prevEnd = endTicks;
816
+ }
817
+ }
818
+ }
819
+
820
+ if ("${trackType}" !== "audio") findGaps(seq.videoTracks, "video");
821
+ if ("${trackType}" !== "video") findGaps(seq.audioTracks, "audio");
822
+
823
+ return __result({
824
+ sequenceName: seq.name,
825
+ gapCount: gaps.length,
826
+ minGapSeconds: ${minGap},
827
+ gaps: gaps
828
+ });
829
829
  `);
830
830
  return sendCommand(script, bridgeOptions);
831
831
  },
@@ -845,133 +845,133 @@ export function getInspectionTools(bridgeOptions) {
845
845
  const seqLookup = args.sequence_id
846
846
  ? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
847
847
  : `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
848
- const script = buildToolScript(`
849
- ${seqLookup}
850
-
851
- var summary = {
852
- name: seq.name,
853
- id: seq.sequenceID,
854
- resolution: seq.frameSizeHorizontal + "x" + seq.frameSizeVertical,
855
- durationSeconds: __ticksToSeconds(seq.end)
856
- };
857
-
858
- try {
859
- var s = seq.getSettings();
860
- if (s) summary.frameRate = s.videoFrameRate;
861
- } catch(e) {}
862
-
863
- // Playhead
864
- try { summary.playheadSeconds = __ticksToSeconds(seq.getPlayerPosition().ticks); } catch(e) {}
865
-
866
- var totalVideoClips = 0;
867
- var totalAudioClips = 0;
868
- var usedMedia = {};
869
- var effectUsage = {};
870
- var disabledClips = 0;
871
- var totalVideoFilled = 0;
872
- var seqEndTicks = parseFloat(seq.end);
873
-
874
- // Video tracks
875
- var videoTrackSummary = [];
876
- for (var t = 0; t < seq.videoTracks.numTracks; t++) {
877
- var track = seq.videoTracks[t];
878
- var trackFilled = 0;
879
- for (var c = 0; c < track.clips.numItems; c++) {
880
- totalVideoClips++;
881
- var clip = track.clips[c];
882
- trackFilled += parseFloat(clip.end.ticks) - parseFloat(clip.start.ticks);
883
- try { if (clip.isDisabled()) disabledClips++; } catch(e) {}
884
- try {
885
- if (clip.projectItem) {
886
- var srcName = clip.projectItem.name;
887
- if (!usedMedia[srcName]) usedMedia[srcName] = 0;
888
- usedMedia[srcName]++;
889
- }
890
- } catch(e) {}
891
- try {
892
- for (var e = 0; e < clip.components.numItems; e++) {
893
- var eName = clip.components[e].displayName;
894
- if (!effectUsage[eName]) effectUsage[eName] = 0;
895
- effectUsage[eName]++;
896
- }
897
- } catch(e) {}
898
- }
899
- if (t === 0) totalVideoFilled = trackFilled;
900
- videoTrackSummary.push({
901
- index: t,
902
- name: track.name,
903
- clipCount: track.clips.numItems,
904
- muted: track.isMuted(),
905
- locked: track.isLocked()
906
- });
907
- }
908
-
909
- // Audio tracks
910
- var audioTrackSummary = [];
911
- for (var t = 0; t < seq.audioTracks.numTracks; t++) {
912
- var track = seq.audioTracks[t];
913
- for (var c = 0; c < track.clips.numItems; c++) {
914
- totalAudioClips++;
915
- var aClip = track.clips[c];
916
- try {
917
- if (aClip.projectItem) {
918
- var srcName = aClip.projectItem.name;
919
- if (!usedMedia[srcName]) usedMedia[srcName] = 0;
920
- usedMedia[srcName]++;
921
- }
922
- } catch(e) {}
923
- }
924
- audioTrackSummary.push({
925
- index: t,
926
- name: track.name,
927
- clipCount: track.clips.numItems,
928
- muted: track.isMuted(),
929
- locked: track.isLocked()
930
- });
931
- }
932
-
933
- summary.totalVideoClips = totalVideoClips;
934
- summary.totalAudioClips = totalAudioClips;
935
- summary.totalClips = totalVideoClips + totalAudioClips;
936
- summary.disabledClips = disabledClips;
937
- summary.videoTrackCount = seq.videoTracks.numTracks;
938
- summary.audioTrackCount = seq.audioTracks.numTracks;
939
- summary.videoTracks = videoTrackSummary;
940
- summary.audioTracks = audioTrackSummary;
941
-
942
- // V1 coverage
943
- if (seqEndTicks > 0) {
944
- summary.v1CoveragePercent = Math.round((totalVideoFilled / seqEndTicks) * 10000) / 100;
945
- }
946
-
947
- // Used media
948
- var mediaList = [];
949
- for (var name in usedMedia) {
950
- if (usedMedia.hasOwnProperty(name)) {
951
- mediaList.push({ name: name, useCount: usedMedia[name] });
952
- }
953
- }
954
- summary.usedMedia = mediaList;
955
- summary.uniqueMediaCount = mediaList.length;
956
-
957
- // Effect usage
958
- var effectList = [];
959
- for (var name in effectUsage) {
960
- if (effectUsage.hasOwnProperty(name)) {
961
- effectList.push({ name: name, count: effectUsage[name] });
962
- }
963
- }
964
- summary.effectUsage = effectList;
965
-
966
- // Markers
967
- var markerCount = 0;
968
- try {
969
- var m = seq.markers.getFirstMarker();
970
- while (m) { markerCount++; m = seq.markers.getNextMarker(m); }
971
- } catch(e) {}
972
- summary.markerCount = markerCount;
973
-
974
- return __result(summary);
848
+ const script = buildToolScript(`
849
+ ${seqLookup}
850
+
851
+ var summary = {
852
+ name: seq.name,
853
+ id: seq.sequenceID,
854
+ resolution: seq.frameSizeHorizontal + "x" + seq.frameSizeVertical,
855
+ durationSeconds: __ticksToSeconds(seq.end)
856
+ };
857
+
858
+ try {
859
+ var s = seq.getSettings();
860
+ if (s) summary.frameRate = s.videoFrameRate;
861
+ } catch(e) {}
862
+
863
+ // Playhead
864
+ try { summary.playheadSeconds = __ticksToSeconds(seq.getPlayerPosition().ticks); } catch(e) {}
865
+
866
+ var totalVideoClips = 0;
867
+ var totalAudioClips = 0;
868
+ var usedMedia = {};
869
+ var effectUsage = {};
870
+ var disabledClips = 0;
871
+ var totalVideoFilled = 0;
872
+ var seqEndTicks = parseFloat(seq.end);
873
+
874
+ // Video tracks
875
+ var videoTrackSummary = [];
876
+ for (var t = 0; t < seq.videoTracks.numTracks; t++) {
877
+ var track = seq.videoTracks[t];
878
+ var trackFilled = 0;
879
+ for (var c = 0; c < track.clips.numItems; c++) {
880
+ totalVideoClips++;
881
+ var clip = track.clips[c];
882
+ trackFilled += parseFloat(clip.end.ticks) - parseFloat(clip.start.ticks);
883
+ try { if (clip.isDisabled()) disabledClips++; } catch(e) {}
884
+ try {
885
+ if (clip.projectItem) {
886
+ var srcName = clip.projectItem.name;
887
+ if (!usedMedia[srcName]) usedMedia[srcName] = 0;
888
+ usedMedia[srcName]++;
889
+ }
890
+ } catch(e) {}
891
+ try {
892
+ for (var e = 0; e < clip.components.numItems; e++) {
893
+ var eName = clip.components[e].displayName;
894
+ if (!effectUsage[eName]) effectUsage[eName] = 0;
895
+ effectUsage[eName]++;
896
+ }
897
+ } catch(e) {}
898
+ }
899
+ if (t === 0) totalVideoFilled = trackFilled;
900
+ videoTrackSummary.push({
901
+ index: t,
902
+ name: track.name,
903
+ clipCount: track.clips.numItems,
904
+ muted: track.isMuted(),
905
+ locked: track.isLocked()
906
+ });
907
+ }
908
+
909
+ // Audio tracks
910
+ var audioTrackSummary = [];
911
+ for (var t = 0; t < seq.audioTracks.numTracks; t++) {
912
+ var track = seq.audioTracks[t];
913
+ for (var c = 0; c < track.clips.numItems; c++) {
914
+ totalAudioClips++;
915
+ var aClip = track.clips[c];
916
+ try {
917
+ if (aClip.projectItem) {
918
+ var srcName = aClip.projectItem.name;
919
+ if (!usedMedia[srcName]) usedMedia[srcName] = 0;
920
+ usedMedia[srcName]++;
921
+ }
922
+ } catch(e) {}
923
+ }
924
+ audioTrackSummary.push({
925
+ index: t,
926
+ name: track.name,
927
+ clipCount: track.clips.numItems,
928
+ muted: track.isMuted(),
929
+ locked: track.isLocked()
930
+ });
931
+ }
932
+
933
+ summary.totalVideoClips = totalVideoClips;
934
+ summary.totalAudioClips = totalAudioClips;
935
+ summary.totalClips = totalVideoClips + totalAudioClips;
936
+ summary.disabledClips = disabledClips;
937
+ summary.videoTrackCount = seq.videoTracks.numTracks;
938
+ summary.audioTrackCount = seq.audioTracks.numTracks;
939
+ summary.videoTracks = videoTrackSummary;
940
+ summary.audioTracks = audioTrackSummary;
941
+
942
+ // V1 coverage
943
+ if (seqEndTicks > 0) {
944
+ summary.v1CoveragePercent = Math.round((totalVideoFilled / seqEndTicks) * 10000) / 100;
945
+ }
946
+
947
+ // Used media
948
+ var mediaList = [];
949
+ for (var name in usedMedia) {
950
+ if (usedMedia.hasOwnProperty(name)) {
951
+ mediaList.push({ name: name, useCount: usedMedia[name] });
952
+ }
953
+ }
954
+ summary.usedMedia = mediaList;
955
+ summary.uniqueMediaCount = mediaList.length;
956
+
957
+ // Effect usage
958
+ var effectList = [];
959
+ for (var name in effectUsage) {
960
+ if (effectUsage.hasOwnProperty(name)) {
961
+ effectList.push({ name: name, count: effectUsage[name] });
962
+ }
963
+ }
964
+ summary.effectUsage = effectList;
965
+
966
+ // Markers
967
+ var markerCount = 0;
968
+ try {
969
+ var m = seq.markers.getFirstMarker();
970
+ while (m) { markerCount++; m = seq.markers.getNextMarker(m); }
971
+ } catch(e) {}
972
+ summary.markerCount = markerCount;
973
+
974
+ return __result(summary);
975
975
  `);
976
976
  return sendCommand(script, bridgeOptions);
977
977
  },
@@ -980,28 +980,28 @@ export function getInspectionTools(bridgeOptions) {
980
980
  description: "Find all offline/missing media in the project with their expected file paths. Essential for diagnosing broken links.",
981
981
  parameters: {},
982
982
  handler: async () => {
983
- const script = buildToolScript(`
984
- var offline = [];
985
- function scan(bin) {
986
- for (var i = 0; i < bin.children.numItems; i++) {
987
- var item = bin.children[i];
988
- try {
989
- if (item.isOffline()) {
990
- var entry = {
991
- nodeId: item.nodeId,
992
- name: item.name,
993
- treePath: item.treePath
994
- };
995
- try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
996
- try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
997
- offline.push(entry);
998
- }
999
- } catch(e) {}
1000
- if (item.type === 2) scan(item);
1001
- }
1002
- }
1003
- scan(app.project.rootItem);
1004
- return __result({ offlineCount: offline.length, items: offline });
983
+ const script = buildToolScript(`
984
+ var offline = [];
985
+ function scan(bin) {
986
+ for (var i = 0; i < bin.children.numItems; i++) {
987
+ var item = bin.children[i];
988
+ try {
989
+ if (item.isOffline()) {
990
+ var entry = {
991
+ nodeId: item.nodeId,
992
+ name: item.name,
993
+ treePath: item.treePath
994
+ };
995
+ try { entry.mediaPath = item.getMediaPath(); } catch(e) {}
996
+ try { entry.colorLabel = item.getColorLabel(); } catch(e) {}
997
+ offline.push(entry);
998
+ }
999
+ } catch(e) {}
1000
+ if (item.type === 2) scan(item);
1001
+ }
1002
+ }
1003
+ scan(app.project.rootItem);
1004
+ return __result({ offlineCount: offline.length, items: offline });
1005
1005
  `);
1006
1006
  return sendCommand(script, bridgeOptions);
1007
1007
  },
@@ -1021,65 +1021,65 @@ export function getInspectionTools(bridgeOptions) {
1021
1021
  const seqLookup = args.sequence_id
1022
1022
  ? `var seq = __findSequence("${escapeForExtendScript(args.sequence_id)}"); if (!seq) return __error("Sequence not found");`
1023
1023
  : `var seq = app.project.activeSequence; if (!seq) return __error("No active sequence");`;
1024
- const script = buildToolScript(`
1025
- ${seqLookup}
1026
-
1027
- var mediaMap = {};
1028
-
1029
- function scanTracks(tracks, trackType) {
1030
- for (var t = 0; t < tracks.numTracks; t++) {
1031
- var track = tracks[t];
1032
- for (var c = 0; c < track.clips.numItems; c++) {
1033
- var clip = track.clips[c];
1034
- try {
1035
- var src = clip.projectItem;
1036
- if (!src) continue;
1037
- var key = src.nodeId;
1038
- if (!mediaMap[key]) {
1039
- mediaMap[key] = {
1040
- nodeId: src.nodeId,
1041
- name: src.name,
1042
- mediaPath: "",
1043
- offline: false,
1044
- useCount: 0,
1045
- tracks: []
1046
- };
1047
- try { mediaMap[key].mediaPath = src.getMediaPath(); } catch(e) {}
1048
- try { mediaMap[key].offline = src.isOffline(); } catch(e) {}
1049
- }
1050
- mediaMap[key].useCount++;
1051
- mediaMap[key].tracks.push(trackType + " " + t);
1052
- } catch(e) {}
1053
- }
1054
- }
1055
- }
1056
-
1057
- scanTracks(seq.videoTracks, "V");
1058
- scanTracks(seq.audioTracks, "A");
1059
-
1060
- var report = [];
1061
- var offlineUsed = 0;
1062
- for (var key in mediaMap) {
1063
- if (mediaMap.hasOwnProperty(key)) {
1064
- // Deduplicate track list
1065
- var unique = {};
1066
- for (var i = 0; i < mediaMap[key].tracks.length; i++) {
1067
- unique[mediaMap[key].tracks[i]] = true;
1068
- }
1069
- var trackList = [];
1070
- for (var k in unique) { if (unique.hasOwnProperty(k)) trackList.push(k); }
1071
- mediaMap[key].tracks = trackList;
1072
- if (mediaMap[key].offline) offlineUsed++;
1073
- report.push(mediaMap[key]);
1074
- }
1075
- }
1076
-
1077
- return __result({
1078
- sequenceName: seq.name,
1079
- uniqueMediaCount: report.length,
1080
- offlineUsedCount: offlineUsed,
1081
- media: report
1082
- });
1024
+ const script = buildToolScript(`
1025
+ ${seqLookup}
1026
+
1027
+ var mediaMap = {};
1028
+
1029
+ function scanTracks(tracks, trackType) {
1030
+ for (var t = 0; t < tracks.numTracks; t++) {
1031
+ var track = tracks[t];
1032
+ for (var c = 0; c < track.clips.numItems; c++) {
1033
+ var clip = track.clips[c];
1034
+ try {
1035
+ var src = clip.projectItem;
1036
+ if (!src) continue;
1037
+ var key = src.nodeId;
1038
+ if (!mediaMap[key]) {
1039
+ mediaMap[key] = {
1040
+ nodeId: src.nodeId,
1041
+ name: src.name,
1042
+ mediaPath: "",
1043
+ offline: false,
1044
+ useCount: 0,
1045
+ tracks: []
1046
+ };
1047
+ try { mediaMap[key].mediaPath = src.getMediaPath(); } catch(e) {}
1048
+ try { mediaMap[key].offline = src.isOffline(); } catch(e) {}
1049
+ }
1050
+ mediaMap[key].useCount++;
1051
+ mediaMap[key].tracks.push(trackType + " " + t);
1052
+ } catch(e) {}
1053
+ }
1054
+ }
1055
+ }
1056
+
1057
+ scanTracks(seq.videoTracks, "V");
1058
+ scanTracks(seq.audioTracks, "A");
1059
+
1060
+ var report = [];
1061
+ var offlineUsed = 0;
1062
+ for (var key in mediaMap) {
1063
+ if (mediaMap.hasOwnProperty(key)) {
1064
+ // Deduplicate track list
1065
+ var unique = {};
1066
+ for (var i = 0; i < mediaMap[key].tracks.length; i++) {
1067
+ unique[mediaMap[key].tracks[i]] = true;
1068
+ }
1069
+ var trackList = [];
1070
+ for (var k in unique) { if (unique.hasOwnProperty(k)) trackList.push(k); }
1071
+ mediaMap[key].tracks = trackList;
1072
+ if (mediaMap[key].offline) offlineUsed++;
1073
+ report.push(mediaMap[key]);
1074
+ }
1075
+ }
1076
+
1077
+ return __result({
1078
+ sequenceName: seq.name,
1079
+ uniqueMediaCount: report.length,
1080
+ offlineUsedCount: offlineUsed,
1081
+ media: report
1082
+ });
1083
1083
  `);
1084
1084
  return sendCommand(script, bridgeOptions);
1085
1085
  },