premiere-cli 0.2.0__py3-none-any.whl

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 (247) hide show
  1. premiere_cli/__init__.py +11 -0
  2. premiere_cli/cli.py +3664 -0
  3. premiere_cli/log.py +66 -0
  4. premiere_cli/panel/.debug +8 -0
  5. premiere_cli/panel/CSXS/manifest.xml +52 -0
  6. premiere_cli/panel/css/style.css +53 -0
  7. premiere_cli/panel/host/commands/add-adjustment-layer.jsx +190 -0
  8. premiere_cli/panel/host/commands/add-audio-keyframes.jsx +176 -0
  9. premiere_cli/panel/host/commands/add-custom-metadata-field.jsx +63 -0
  10. premiere_cli/panel/host/commands/add-keyframe.jsx +181 -0
  11. premiere_cli/panel/host/commands/add-marker-to-project-item.jsx +194 -0
  12. premiere_cli/panel/host/commands/add-marker.jsx +129 -0
  13. premiere_cli/panel/host/commands/add-text-overlay.jsx +101 -0
  14. premiere_cli/panel/host/commands/add-to-render-queue.jsx +120 -0
  15. premiere_cli/panel/host/commands/add-to-timeline.jsx +300 -0
  16. premiere_cli/panel/host/commands/add-track.jsx +188 -0
  17. premiere_cli/panel/host/commands/add-transition.jsx +134 -0
  18. premiere_cli/panel/host/commands/adjust-audio-levels.jsx +132 -0
  19. premiere_cli/panel/host/commands/apply-audio-effect.jsx +118 -0
  20. premiere_cli/panel/host/commands/apply-effect.jsx +122 -0
  21. premiere_cli/panel/host/commands/apply-lut.jsx +107 -0
  22. premiere_cli/panel/host/commands/attach-custom-property.jsx +66 -0
  23. premiere_cli/panel/host/commands/auto-reframe-sequence.jsx +124 -0
  24. premiere_cli/panel/host/commands/batch-add-transitions.jsx +158 -0
  25. premiere_cli/panel/host/commands/batch-apply-effect.jsx +182 -0
  26. premiere_cli/panel/host/commands/batch-rename-clips.jsx +170 -0
  27. premiere_cli/panel/host/commands/batch-set-clips-enabled.jsx +145 -0
  28. premiere_cli/panel/host/commands/clear-item-in-out.jsx +117 -0
  29. premiere_cli/panel/host/commands/clear-sequence-in-out.jsx +100 -0
  30. premiere_cli/panel/host/commands/close-all-source-clips.jsx +32 -0
  31. premiere_cli/panel/host/commands/close-sequence.jsx +80 -0
  32. premiere_cli/panel/host/commands/close-source-monitor.jsx +32 -0
  33. premiere_cli/panel/host/commands/color-correct.jsx +164 -0
  34. premiere_cli/panel/host/commands/copy-effect-values.jsx +183 -0
  35. premiere_cli/panel/host/commands/copy-effects-between-clips.jsx +234 -0
  36. premiere_cli/panel/host/commands/create-bars-and-tone.jsx +152 -0
  37. premiere_cli/panel/host/commands/create-bin.jsx +76 -0
  38. premiere_cli/panel/host/commands/create-caption-track.jsx +159 -0
  39. premiere_cli/panel/host/commands/create-sequence-from-clips.jsx +170 -0
  40. premiere_cli/panel/host/commands/create-sequence-from-preset.jsx +90 -0
  41. premiere_cli/panel/host/commands/create-sequence.jsx +166 -0
  42. premiere_cli/panel/host/commands/create-smart-bin.jsx +80 -0
  43. premiere_cli/panel/host/commands/create-subclip.jsx +248 -0
  44. premiere_cli/panel/host/commands/create-subsequence.jsx +136 -0
  45. premiere_cli/panel/host/commands/debug-qe-inspect.jsx +248 -0
  46. premiere_cli/panel/host/commands/debug-qe-try-mutate.jsx +305 -0
  47. premiere_cli/panel/host/commands/delete-marker.jsx +178 -0
  48. premiere_cli/panel/host/commands/deselect-all-clips.jsx +98 -0
  49. premiere_cli/panel/host/commands/detach-proxy.jsx +116 -0
  50. premiere_cli/panel/host/commands/duplicate-clip.jsx +140 -0
  51. premiere_cli/panel/host/commands/duplicate-sequence.jsx +150 -0
  52. premiere_cli/panel/host/commands/encode-file.jsx +86 -0
  53. premiere_cli/panel/host/commands/encode-project-item.jsx +145 -0
  54. premiere_cli/panel/host/commands/export-aaf.jsx +77 -0
  55. premiere_cli/panel/host/commands/export-fcp-xml.jsx +65 -0
  56. premiere_cli/panel/host/commands/export-frame.jsx +381 -0
  57. premiere_cli/panel/host/commands/export-omf.jsx +95 -0
  58. premiere_cli/panel/host/commands/export-sequence-as-project.jsx +65 -0
  59. premiere_cli/panel/host/commands/export-sequence.jsx +100 -0
  60. premiere_cli/panel/host/commands/extract-audio-track.jsx +181 -0
  61. premiere_cli/panel/host/commands/extract-selection.jsx +113 -0
  62. premiere_cli/panel/host/commands/find-items-by-media-path.jsx +112 -0
  63. premiere_cli/panel/host/commands/freeze-frame.jsx +215 -0
  64. premiere_cli/panel/host/commands/get-active-sequence.jsx +103 -0
  65. premiere_cli/panel/host/commands/get-all-project-paths.jsx +72 -0
  66. premiere_cli/panel/host/commands/get-bin-contents.jsx +176 -0
  67. premiere_cli/panel/host/commands/get-clip-adjustment-layer.jsx +83 -0
  68. premiere_cli/panel/host/commands/get-clip-at-playhead.jsx +99 -0
  69. premiere_cli/panel/host/commands/get-clip-at-position.jsx +120 -0
  70. premiere_cli/panel/host/commands/get-clip-links.jsx +135 -0
  71. premiere_cli/panel/host/commands/get-clip-markers.jsx +144 -0
  72. premiere_cli/panel/host/commands/get-clip-speed.jsx +69 -0
  73. premiere_cli/panel/host/commands/get-color-label.jsx +89 -0
  74. premiere_cli/panel/host/commands/get-color-space.jsx +99 -0
  75. premiere_cli/panel/host/commands/get-duplicate-media.jsx +78 -0
  76. premiere_cli/panel/host/commands/get-effect-properties.jsx +129 -0
  77. premiere_cli/panel/host/commands/get-encoder-presets.jsx +131 -0
  78. premiere_cli/panel/host/commands/get-export-file-extension.jsx +56 -0
  79. premiere_cli/panel/host/commands/get-footage-interpretation.jsx +113 -0
  80. premiere_cli/panel/host/commands/get-full-clip-info.jsx +162 -0
  81. premiere_cli/panel/host/commands/get-full-project-overview.jsx +193 -0
  82. premiere_cli/panel/host/commands/get-full-sequence-info.jsx +184 -0
  83. premiere_cli/panel/host/commands/get-graphics-white-luminance.jsx +31 -0
  84. premiere_cli/panel/host/commands/get-insertion-bin.jsx +35 -0
  85. premiere_cli/panel/host/commands/get-item-metadata.jsx +94 -0
  86. premiere_cli/panel/host/commands/get-keyframes.jsx +158 -0
  87. premiere_cli/panel/host/commands/get-mogrt-component.jsx +111 -0
  88. premiere_cli/panel/host/commands/get-next-edit-point.jsx +131 -0
  89. premiere_cli/panel/host/commands/get-offline-media.jsx +67 -0
  90. premiere_cli/panel/host/commands/get-open-projects.jsx +50 -0
  91. premiere_cli/panel/host/commands/get-premiere-state.jsx +164 -0
  92. premiere_cli/panel/host/commands/get-project-info.jsx +63 -0
  93. premiere_cli/panel/host/commands/get-project-item-info.jsx +247 -0
  94. premiere_cli/panel/host/commands/get-project-panel-metadata.jsx +30 -0
  95. premiere_cli/panel/host/commands/get-qe-clip-info.jsx +198 -0
  96. premiere_cli/panel/host/commands/get-render-queue-status.jsx +35 -0
  97. premiere_cli/panel/host/commands/get-sequence-count.jsx +24 -0
  98. premiere_cli/panel/host/commands/get-sequence-in-out.jsx +76 -0
  99. premiere_cli/panel/host/commands/get-sequence-markers-by-type.jsx +89 -0
  100. premiere_cli/panel/host/commands/get-source-monitor-info.jsx +34 -0
  101. premiere_cli/panel/host/commands/get-source-monitor-position.jsx +30 -0
  102. premiere_cli/panel/host/commands/get-target-tracks.jsx +76 -0
  103. premiere_cli/panel/host/commands/get-timeline-gaps.jsx +124 -0
  104. premiere_cli/panel/host/commands/get-timeline-summary.jsx +154 -0
  105. premiere_cli/panel/host/commands/get-total-clip-count.jsx +67 -0
  106. premiere_cli/panel/host/commands/get-track-info.jsx +117 -0
  107. premiere_cli/panel/host/commands/get-unused-media.jsx +99 -0
  108. premiere_cli/panel/host/commands/get-used-media-report.jsx +125 -0
  109. premiere_cli/panel/host/commands/get-value-at-time.jsx +135 -0
  110. premiere_cli/panel/host/commands/get-version-info.jsx +33 -0
  111. premiere_cli/panel/host/commands/get-work-area.jsx +52 -0
  112. premiere_cli/panel/host/commands/get-workspaces.jsx +29 -0
  113. premiere_cli/panel/host/commands/get-xmp-metadata.jsx +107 -0
  114. premiere_cli/panel/host/commands/import-ae-comps.jsx +129 -0
  115. premiere_cli/panel/host/commands/import-fcp-xml.jsx +103 -0
  116. premiere_cli/panel/host/commands/import-folder.jsx +193 -0
  117. premiere_cli/panel/host/commands/import-image-sequence.jsx +171 -0
  118. premiere_cli/panel/host/commands/import-media.jsx +217 -0
  119. premiere_cli/panel/host/commands/import-mogrt-from-library.jsx +105 -0
  120. premiere_cli/panel/host/commands/import-mogrt.jsx +111 -0
  121. premiere_cli/panel/host/commands/import-sequences-from-project.jsx +80 -0
  122. premiere_cli/panel/host/commands/insert-from-source.jsx +162 -0
  123. premiere_cli/panel/host/commands/inspect-dom-object.jsx +162 -0
  124. premiere_cli/panel/host/commands/invert-selection.jsx +114 -0
  125. premiere_cli/panel/host/commands/is-work-area-enabled.jsx +88 -0
  126. premiere_cli/panel/host/commands/lift-selection.jsx +106 -0
  127. premiere_cli/panel/host/commands/link-selection.jsx +111 -0
  128. premiere_cli/panel/host/commands/list-available-audio-effects.jsx +33 -0
  129. premiere_cli/panel/host/commands/list-available-audio-transitions.jsx +35 -0
  130. premiere_cli/panel/host/commands/list-available-effects.jsx +33 -0
  131. premiere_cli/panel/host/commands/list-available-transitions.jsx +74 -0
  132. premiere_cli/panel/host/commands/list-markers.jsx +69 -0
  133. premiere_cli/panel/host/commands/list-project-items.jsx +105 -0
  134. premiere_cli/panel/host/commands/lock-track.jsx +114 -0
  135. premiere_cli/panel/host/commands/manage-proxies.jsx +176 -0
  136. premiere_cli/panel/host/commands/match-frame.jsx +141 -0
  137. premiere_cli/panel/host/commands/move-clip-to-track.jsx +220 -0
  138. premiere_cli/panel/host/commands/move-clip.jsx +97 -0
  139. premiere_cli/panel/host/commands/move-items-to-bin.jsx +194 -0
  140. premiere_cli/panel/host/commands/move-playhead-to-edit.jsx +174 -0
  141. premiere_cli/panel/host/commands/move-playhead.jsx +137 -0
  142. premiere_cli/panel/host/commands/nest-clips.jsx +179 -0
  143. premiere_cli/panel/host/commands/open-in-source.jsx +117 -0
  144. premiere_cli/panel/host/commands/open-project.jsx +61 -0
  145. premiere_cli/panel/host/commands/overwrite-clip-at.jsx +350 -0
  146. premiere_cli/panel/host/commands/overwrite-from-source.jsx +150 -0
  147. premiere_cli/panel/host/commands/play-source-monitor.jsx +36 -0
  148. premiere_cli/panel/host/commands/play-timeline.jsx +24 -0
  149. premiere_cli/panel/host/commands/razor-all-tracks.jsx +171 -0
  150. premiere_cli/panel/host/commands/redo.jsx +69 -0
  151. premiere_cli/panel/host/commands/refresh-media.jsx +101 -0
  152. premiere_cli/panel/host/commands/relink-media.jsx +132 -0
  153. premiere_cli/panel/host/commands/remove-all-effects.jsx +114 -0
  154. premiere_cli/panel/host/commands/remove-effect-by-name.jsx +143 -0
  155. premiere_cli/panel/host/commands/remove-effect.jsx +122 -0
  156. premiere_cli/panel/host/commands/remove-from-timeline.jsx +93 -0
  157. premiere_cli/panel/host/commands/remove-keyframe-range.jsx +173 -0
  158. premiere_cli/panel/host/commands/remove-keyframe.jsx +192 -0
  159. premiere_cli/panel/host/commands/remove-selected-clips.jsx +126 -0
  160. premiere_cli/panel/host/commands/remove-track-intervals.jsx +254 -0
  161. premiere_cli/panel/host/commands/remove-transition.jsx +164 -0
  162. premiere_cli/panel/host/commands/rename-bin.jsx +88 -0
  163. premiere_cli/panel/host/commands/rename-clip.jsx +127 -0
  164. premiere_cli/panel/host/commands/rename-project-item.jsx +111 -0
  165. premiere_cli/panel/host/commands/rename-track.jsx +84 -0
  166. premiere_cli/panel/host/commands/replace-clip-media.jsx +140 -0
  167. premiere_cli/panel/host/commands/replace-clip.jsx +188 -0
  168. premiere_cli/panel/host/commands/reverse-clip.jsx +187 -0
  169. premiere_cli/panel/host/commands/ripple-delete-clip.jsx +156 -0
  170. premiere_cli/panel/host/commands/roll-edit.jsx +162 -0
  171. premiere_cli/panel/host/commands/save-project-as.jsx +55 -0
  172. premiere_cli/panel/host/commands/save-project.jsx +57 -0
  173. premiere_cli/panel/host/commands/scene-edit-detection.jsx +128 -0
  174. premiere_cli/panel/host/commands/search-project-items.jsx +180 -0
  175. premiere_cli/panel/host/commands/select-all-clips.jsx +107 -0
  176. premiere_cli/panel/host/commands/select-clips-by-color.jsx +142 -0
  177. premiere_cli/panel/host/commands/select-clips-by-name.jsx +133 -0
  178. premiere_cli/panel/host/commands/select-clips-in-range.jsx +133 -0
  179. premiere_cli/panel/host/commands/select-disabled-clips.jsx +127 -0
  180. premiere_cli/panel/host/commands/select-project-item.jsx +115 -0
  181. premiere_cli/panel/host/commands/set-active-project.jsx +184 -0
  182. premiere_cli/panel/host/commands/set-active-sequence.jsx +87 -0
  183. premiere_cli/panel/host/commands/set-all-tracks-targeted.jsx +112 -0
  184. premiere_cli/panel/host/commands/set-anti-alias-quality.jsx +125 -0
  185. premiere_cli/panel/host/commands/set-blend-mode.jsx +111 -0
  186. premiere_cli/panel/host/commands/set-clip-anchor-point.jsx +102 -0
  187. premiere_cli/panel/host/commands/set-clip-enabled.jsx +127 -0
  188. premiere_cli/panel/host/commands/set-clip-opacity.jsx +102 -0
  189. premiere_cli/panel/host/commands/set-clip-pan.jsx +107 -0
  190. premiere_cli/panel/host/commands/set-clip-position.jsx +103 -0
  191. premiere_cli/panel/host/commands/set-clip-properties.jsx +221 -0
  192. premiere_cli/panel/host/commands/set-clip-rotation.jsx +102 -0
  193. premiere_cli/panel/host/commands/set-clip-scale.jsx +102 -0
  194. premiere_cli/panel/host/commands/set-clip-selection.jsx +144 -0
  195. premiere_cli/panel/host/commands/set-clip-speed.jsx +160 -0
  196. premiere_cli/panel/host/commands/set-clip-volume.jsx +128 -0
  197. premiere_cli/panel/host/commands/set-color-label.jsx +123 -0
  198. premiere_cli/panel/host/commands/set-color-value.jsx +155 -0
  199. premiere_cli/panel/host/commands/set-effect-property.jsx +124 -0
  200. premiere_cli/panel/host/commands/set-footage-interpretation.jsx +173 -0
  201. premiere_cli/panel/host/commands/set-frame-blend.jsx +145 -0
  202. premiere_cli/panel/host/commands/set-graphics-white-luminance.jsx +73 -0
  203. premiere_cli/panel/host/commands/set-item-in-out.jsx +180 -0
  204. premiere_cli/panel/host/commands/set-item-metadata.jsx +134 -0
  205. premiere_cli/panel/host/commands/set-item-offline.jsx +109 -0
  206. premiere_cli/panel/host/commands/set-item-start-time.jsx +139 -0
  207. premiere_cli/panel/host/commands/set-keyframe-interpolation.jsx +186 -0
  208. premiere_cli/panel/host/commands/set-override-frame-rate.jsx +123 -0
  209. premiere_cli/panel/host/commands/set-override-pixel-aspect-ratio.jsx +129 -0
  210. premiere_cli/panel/host/commands/set-poster-frame.jsx +192 -0
  211. premiere_cli/panel/host/commands/set-project-panel-metadata.jsx +69 -0
  212. premiere_cli/panel/host/commands/set-scale-to-frame-size.jsx +101 -0
  213. premiere_cli/panel/host/commands/set-scale-width-height.jsx +140 -0
  214. premiere_cli/panel/host/commands/set-sequence-in-out.jsx +65 -0
  215. premiere_cli/panel/host/commands/set-sequence-settings.jsx +184 -0
  216. premiere_cli/panel/host/commands/set-source-in-out.jsx +98 -0
  217. premiere_cli/panel/host/commands/set-target-track.jsx +91 -0
  218. premiere_cli/panel/host/commands/set-time-interpolation.jsx +141 -0
  219. premiere_cli/panel/host/commands/set-track-mute.jsx +91 -0
  220. premiere_cli/panel/host/commands/set-track-visibility.jsx +94 -0
  221. premiere_cli/panel/host/commands/set-transcode-on-ingest.jsx +78 -0
  222. premiere_cli/panel/host/commands/set-uniform-scale.jsx +104 -0
  223. premiere_cli/panel/host/commands/set-work-area.jsx +76 -0
  224. premiere_cli/panel/host/commands/set-workspace.jsx +35 -0
  225. premiere_cli/panel/host/commands/set-xmp-metadata.jsx +157 -0
  226. premiere_cli/panel/host/commands/slide-edit.jsx +162 -0
  227. premiere_cli/panel/host/commands/slip-edit.jsx +167 -0
  228. premiere_cli/panel/host/commands/split-clip.jsx +144 -0
  229. premiere_cli/panel/host/commands/stabilize-clip.jsx +139 -0
  230. premiere_cli/panel/host/commands/stop-playback.jsx +23 -0
  231. premiere_cli/panel/host/commands/trim-clip.jsx +111 -0
  232. premiere_cli/panel/host/commands/undo.jsx +114 -0
  233. premiere_cli/panel/host/commands/unlink-selection.jsx +106 -0
  234. premiere_cli/panel/host/commands/unnest-sequence.jsx +207 -0
  235. premiere_cli/panel/host/commands/update-marker.jsx +120 -0
  236. premiere_cli/panel/host/index.jsx +1227 -0
  237. premiere_cli/panel/host/presets/default-4k-25fps.sqpreset +63 -0
  238. premiere_cli/panel/index.html +16 -0
  239. premiere_cli/panel/js/cs-interface.js +11 -0
  240. premiere_cli/panel/js/main.js +409 -0
  241. premiere_cli/panel_install.py +220 -0
  242. premiere_cli-0.2.0.dist-info/METADATA +127 -0
  243. premiere_cli-0.2.0.dist-info/RECORD +247 -0
  244. premiere_cli-0.2.0.dist-info/WHEEL +5 -0
  245. premiere_cli-0.2.0.dist-info/entry_points.txt +3 -0
  246. premiere_cli-0.2.0.dist-info/licenses/LICENSE +428 -0
  247. premiere_cli-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,74 @@
1
+ // Command: list-available-transitions → ppb_listAvailableTransitions
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (ensureQEEnabled, ...)
4
+ // are already defined there.
5
+ //
6
+ // QE-only enumeration: qe.project.getVideoTransitionList(). Per
7
+ // PREMIERE_API_NOTES.md, PPro 2026 is known to return an EMPTY list here
8
+ // even though by-name lookup (getVideoTransitionByName) still resolves
9
+ // real transitions — an empty result is surfaced honestly (source:
10
+ // "list") rather than treated as an error, and a probe of common
11
+ // transition names via getVideoTransitionByName is appended as a
12
+ // best-effort fallback (source: "byName") when the list came back empty.
13
+
14
+ var PPB_LIST_TRANSITIONS_PROBE_NAMES = [
15
+ "Cross Dissolve", "Dip to Black", "Dip to White", "Film Dissolve",
16
+ "Additive Dissolve", "Morph Cut", "Push", "Slide", "Wipe",
17
+ "Iris Round", "Iris Box"
18
+ ];
19
+
20
+ function ppb_listAvailableTransitions(argsJson) {
21
+ try {
22
+ ensureQEEnabled();
23
+
24
+ if (typeof qe === "undefined" || !qe.project) {
25
+ return JSON.stringify({ ok: false, error: "QE DOM not available (app.enableQE() did not expose qe.project)" });
26
+ }
27
+
28
+ var transitions = [];
29
+ var listError = null;
30
+ try {
31
+ var list = qe.project.getVideoTransitionList();
32
+ for (var i = 0; i < list.numItems; i++) {
33
+ var entry = { name: null, index: i, source: "list" };
34
+ try { entry.name = list[i].name; } catch (e) { entry.name = null; }
35
+ transitions.push(entry);
36
+ }
37
+ } catch (e) {
38
+ listError = e.toString();
39
+ }
40
+
41
+ var probedByName = false;
42
+ if (transitions.length === 0) {
43
+ try {
44
+ if (qe.project.getVideoTransitionByName) {
45
+ probedByName = true;
46
+ for (var n = 0; n < PPB_LIST_TRANSITIONS_PROBE_NAMES.length; n++) {
47
+ try {
48
+ var found = qe.project.getVideoTransitionByName(PPB_LIST_TRANSITIONS_PROBE_NAMES[n]);
49
+ if (found) {
50
+ transitions.push({ name: PPB_LIST_TRANSITIONS_PROBE_NAMES[n], index: null, source: "byName" });
51
+ }
52
+ } catch (e2) {
53
+ // this probe name isn't available on this build — skip it
54
+ }
55
+ }
56
+ }
57
+ } catch (e3) {
58
+ // leave probedByName as-is
59
+ }
60
+ }
61
+
62
+ return JSON.stringify({
63
+ ok: true,
64
+ result: {
65
+ transitions: transitions,
66
+ count: transitions.length,
67
+ listError: listError,
68
+ probedByName: probedByName
69
+ }
70
+ });
71
+ } catch (e) {
72
+ return JSON.stringify({ ok: false, error: e.toString() });
73
+ }
74
+ }
@@ -0,0 +1,69 @@
1
+ // Command: list-markers → ppb_listMarkers
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (TICKS_PER_SECOND,
4
+ // findSequenceByName, timeValueToSeconds, ...) are already defined there.
5
+ //
6
+ // Standard-DOM read only. Same marker iteration pattern as
7
+ // get-full-sequence-info.jsx (getFirstMarker/getNextMarker, capped at
8
+ // 10000 to guard against a pathological linked list) — duplicated locally
9
+ // since each command file loads independently and cannot rely on helpers
10
+ // defined only in another command file.
11
+
12
+ function ppbListMarkers_serialize(seq) {
13
+ var markers = [];
14
+ var m = seq.markers.getFirstMarker();
15
+ var iterations = 0;
16
+ while (m !== null && typeof m !== "undefined" && iterations < 10000) {
17
+ var entry = { name: null, comments: null, type: null, startSeconds: null, endSeconds: null, guid: null };
18
+ try { entry.name = m.name; } catch (e) { entry.name = null; }
19
+ try { entry.comments = m.comments; } catch (e) { entry.comments = null; }
20
+ try { entry.type = m.type; } catch (e) { entry.type = null; }
21
+ try { entry.startSeconds = timeValueToSeconds(m.start); } catch (e) { entry.startSeconds = null; }
22
+ try { entry.endSeconds = timeValueToSeconds(m.end); } catch (e) { entry.endSeconds = null; }
23
+ try { entry.guid = m.guid; } catch (e) { entry.guid = null; }
24
+ markers.push(entry);
25
+
26
+ m = seq.markers.getNextMarker(m);
27
+ iterations++;
28
+ }
29
+ return markers;
30
+ }
31
+
32
+ function ppb_listMarkers(argsJson) {
33
+ try {
34
+ var args;
35
+ try {
36
+ args = JSON.parse(argsJson);
37
+ } catch (e) {
38
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
39
+ }
40
+
41
+ if (!app.project) {
42
+ return JSON.stringify({ ok: false, error: "no project open" });
43
+ }
44
+
45
+ var seq = null;
46
+ if (args.sequenceName && typeof args.sequenceName === "string") {
47
+ seq = findSequenceByName(args.sequenceName);
48
+ if (!seq) {
49
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
50
+ }
51
+ } else {
52
+ seq = app.project.activeSequence;
53
+ if (!seq) {
54
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
55
+ }
56
+ }
57
+
58
+ var markers = [];
59
+ try {
60
+ markers = ppbListMarkers_serialize(seq);
61
+ } catch (e) {
62
+ return JSON.stringify({ ok: false, error: "failed to read markers: " + e.toString() });
63
+ }
64
+
65
+ return JSON.stringify({ ok: true, result: { sequenceName: seq.name, markers: markers, markerCount: markers.length } });
66
+ } catch (e) {
67
+ return JSON.stringify({ ok: false, error: e.toString() });
68
+ }
69
+ }
@@ -0,0 +1,105 @@
1
+ // Command: list-project-items → ppb_listProjectItems
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (TICKS_PER_SECOND,
4
+ // ensureQEEnabled, findSequenceByName, ...) are already defined there.
5
+ //
6
+ // Recursive depth-first walk of app.project.rootItem.children, descending
7
+ // into bins. Helper names are prefixed ppbListProjectItems_ to avoid
8
+ // colliding with same-purpose helpers in other lazily-loaded command files
9
+ // evaluated into this same global context.
10
+
11
+ function ppbListProjectItems_typeToString(item) {
12
+ var raw = item.type;
13
+ try {
14
+ if (typeof ProjectItemType !== "undefined") {
15
+ if (raw === ProjectItemType.BIN) {
16
+ return "BIN";
17
+ }
18
+ if (raw === ProjectItemType.CLIP) {
19
+ return "CLIP";
20
+ }
21
+ if (raw === ProjectItemType.FILE) {
22
+ return "FILE";
23
+ }
24
+ if (raw === ProjectItemType.ROOT) {
25
+ return "ROOT";
26
+ }
27
+ }
28
+ } catch (e) {
29
+ // fall through to raw number below
30
+ }
31
+ return String(raw);
32
+ }
33
+
34
+ function ppbListProjectItems_isBin(item) {
35
+ try {
36
+ return typeof ProjectItemType !== "undefined" && item.type === ProjectItemType.BIN;
37
+ } catch (e) {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ // Capped at depth 32 to defend against pathological/circular bin
43
+ // structures rather than looping forever.
44
+ function ppbListProjectItems_walk(item, parentPath, depth, results) {
45
+ if (depth > 32) {
46
+ return;
47
+ }
48
+
49
+ var treePath = null;
50
+ try {
51
+ treePath = item.treePath;
52
+ } catch (e) {
53
+ treePath = null;
54
+ }
55
+ if (!treePath) {
56
+ treePath = parentPath + "/" + item.name;
57
+ }
58
+
59
+ var isSequence = null;
60
+ try {
61
+ isSequence = item.isSequence();
62
+ } catch (e) {
63
+ isSequence = null;
64
+ }
65
+
66
+ var mediaPath = null;
67
+ try {
68
+ mediaPath = item.getMediaPath();
69
+ } catch (e) {
70
+ mediaPath = null;
71
+ }
72
+
73
+ results.push({
74
+ name: item.name,
75
+ treePath: treePath,
76
+ nodeId: item.nodeId,
77
+ type: ppbListProjectItems_typeToString(item),
78
+ isSequence: isSequence,
79
+ mediaPath: mediaPath
80
+ });
81
+
82
+ if (ppbListProjectItems_isBin(item) && item.children) {
83
+ for (var i = 0; i < item.children.numItems; i++) {
84
+ ppbListProjectItems_walk(item.children[i], treePath, depth + 1, results);
85
+ }
86
+ }
87
+ }
88
+
89
+ function ppb_listProjectItems(argsJson) {
90
+ try {
91
+ if (!app.project) {
92
+ return JSON.stringify({ ok: false, error: "no project open" });
93
+ }
94
+
95
+ var results = [];
96
+ var root = app.project.rootItem;
97
+ for (var i = 0; i < root.children.numItems; i++) {
98
+ ppbListProjectItems_walk(root.children[i], "", 1, results);
99
+ }
100
+
101
+ return JSON.stringify({ ok: true, result: { items: results, count: results.length } });
102
+ } catch (e) {
103
+ return JSON.stringify({ ok: false, error: e.toString() });
104
+ }
105
+ }
@@ -0,0 +1,114 @@
1
+ // Command: lock-track → ppb_lockTrack
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // ...) are already defined there.
5
+ //
6
+ // Standard-DOM mutation. Ported from leancoderkavy's premiere-pro-mcp
7
+ // `lock_track` tool (tracks.ts), generalized here to accept trackType
8
+ // video|audio (the reference only locked video tracks) since
9
+ // track.setLocked() is not video-specific. Tries setLocked(1|0) then
10
+ // setLock(bool) [ayushozha probes both; our build's QE reflect list shows
11
+ // "setLock" so the standard-DOM equivalent may or may not share the name —
12
+ // try both rather than assume]. Verified by reading isLocked() back.
13
+ function ppb_lockTrack(argsJson) {
14
+ try {
15
+ var args;
16
+ try {
17
+ args = JSON.parse(argsJson);
18
+ } catch (e) {
19
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
20
+ }
21
+
22
+ if (args.trackType !== "video" && args.trackType !== "audio") {
23
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
24
+ }
25
+ if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
26
+ return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
27
+ }
28
+ if (typeof args.locked !== "boolean") {
29
+ return JSON.stringify({ ok: false, error: "locked must be a boolean" });
30
+ }
31
+
32
+ if (!app.project) {
33
+ return JSON.stringify({ ok: false, error: "no project open" });
34
+ }
35
+
36
+ var seq = null;
37
+ if (args.sequenceName && typeof args.sequenceName === "string") {
38
+ seq = findSequenceByName(args.sequenceName);
39
+ if (!seq) {
40
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
41
+ }
42
+ } else {
43
+ seq = app.project.activeSequence;
44
+ if (!seq) {
45
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
46
+ }
47
+ }
48
+
49
+ var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
50
+ var numTracks = trackCollection.numTracks;
51
+ if (args.trackIndex >= numTracks) {
52
+ return JSON.stringify({
53
+ ok: false,
54
+ error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
55
+ });
56
+ }
57
+
58
+ var track = trackCollection[args.trackIndex];
59
+ var attempts = [];
60
+ var applied = false;
61
+
62
+ try {
63
+ track.setLocked(args.locked ? 1 : 0);
64
+ attempts.push({ form: "setLocked", success: true });
65
+ applied = true;
66
+ } catch (e) {
67
+ attempts.push({ form: "setLocked", success: false, error: e.toString() });
68
+ }
69
+
70
+ if (!applied) {
71
+ try {
72
+ track.setLock(args.locked);
73
+ attempts.push({ form: "setLock", success: true });
74
+ applied = true;
75
+ } catch (e) {
76
+ attempts.push({ form: "setLock", success: false, error: e.toString() });
77
+ }
78
+ }
79
+
80
+ if (!applied) {
81
+ return JSON.stringify({
82
+ ok: false,
83
+ error: "could not lock/unlock the track with any known form (setLocked, setLock)",
84
+ attempts: attempts
85
+ });
86
+ }
87
+
88
+ var isLockedNow = null;
89
+ try {
90
+ isLockedNow = track.isLocked();
91
+ } catch (e) {
92
+ isLockedNow = null;
93
+ }
94
+
95
+ var result = {
96
+ sequenceName: seq.name,
97
+ trackType: args.trackType,
98
+ trackIndex: args.trackIndex,
99
+ trackName: null,
100
+ requestedLocked: args.locked,
101
+ isLocked: isLockedNow,
102
+ attempts: attempts
103
+ };
104
+ try { result.trackName = track.name; } catch (e) { result.trackName = null; }
105
+
106
+ if (isLockedNow !== null && isLockedNow !== args.locked) {
107
+ result.warning = "isLocked() read back " + isLockedNow + " after requesting " + args.locked + " — mutation may not have taken effect";
108
+ }
109
+
110
+ return JSON.stringify({ ok: true, result: result });
111
+ } catch (e) {
112
+ return JSON.stringify({ ok: false, error: e.toString() });
113
+ }
114
+ }
@@ -0,0 +1,176 @@
1
+ // Command: manage-proxies → ppb_manageProxies
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context.
4
+ //
5
+ // Three distinct, unrelated semantics per action (deliberately narrower
6
+ // than the reference tool this ports, leancoderkavy's premiere-pro-mcp
7
+ // manage_proxies, which also offers a "create" action — dropped here since
8
+ // it's just add-to-render-queue/encode-project-item aimed at a proxy
9
+ // preset with an extra manual "attach once AME finishes" step; compose
10
+ // those existing commands instead of duplicating the fire-and-forget
11
+ // caveat a third time):
12
+ //
13
+ // - "attach": attaches an ALREADY-RENDERED proxy file to one project
14
+ // item via item.attachProxy(path, isHiRes01) (PREMIERE_API_NOTES.md
15
+ // line 285). Requires nodeId/name (item) + proxyPath. Verified via a
16
+ // hasProxy()/getProxyPath() read-back where available.
17
+ // - "enable": turns proxy playback ON project-wide via
18
+ // app.project.setProxyEnabled(true). No item required.
19
+ // - "disable": turns proxy playback OFF project-wide via
20
+ // app.project.setProxyEnabled(false). No item required.
21
+
22
+ // Project-item addressing (nodeId or name) — duplicated per command file,
23
+ // same walk as get-item-metadata.jsx's ppbFindItemGetItemMetadata_*
24
+ // helpers, prefixed for this file.
25
+ function ppbFindItemManageProxies_walk(item, args, depth) {
26
+ if (depth > 32) {
27
+ return null;
28
+ }
29
+ var isBin = false;
30
+ try {
31
+ isBin = typeof ProjectItemType !== "undefined" && item.type === ProjectItemType.BIN;
32
+ } catch (e) {
33
+ isBin = false;
34
+ }
35
+ var matched = false;
36
+ if (args.nodeId !== null) {
37
+ try { matched = item.nodeId === args.nodeId; } catch (e) { matched = false; }
38
+ } else if (args.name !== null) {
39
+ try { matched = item.name === args.name; } catch (e) { matched = false; }
40
+ }
41
+ if (matched) {
42
+ return item;
43
+ }
44
+ if (isBin && item.children) {
45
+ for (var i = 0; i < item.children.numItems; i++) {
46
+ var found = ppbFindItemManageProxies_walk(item.children[i], args, depth + 1);
47
+ if (found) {
48
+ return found;
49
+ }
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+
55
+ function ppbFindItemManageProxies_resolve(args) {
56
+ var root = app.project.rootItem;
57
+ for (var i = 0; i < root.children.numItems; i++) {
58
+ var found = ppbFindItemManageProxies_walk(root.children[i], args, 1);
59
+ if (found) {
60
+ return found;
61
+ }
62
+ }
63
+ return null;
64
+ }
65
+
66
+ function ppb_manageProxies(argsJson) {
67
+ try {
68
+ var args;
69
+ try {
70
+ args = JSON.parse(argsJson);
71
+ } catch (e) {
72
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
73
+ }
74
+
75
+ if (!args.action || (args.action !== "attach" && args.action !== "enable" && args.action !== "disable")) {
76
+ return JSON.stringify({ ok: false, error: "action must be one of \"attach\", \"enable\", \"disable\"" });
77
+ }
78
+
79
+ if (!app.project) {
80
+ return JSON.stringify({ ok: false, error: "no project open" });
81
+ }
82
+
83
+ if (args.action === "enable" || args.action === "disable") {
84
+ var enabled = args.action === "enable";
85
+ try {
86
+ app.project.setProxyEnabled(enabled);
87
+ } catch (e) {
88
+ return JSON.stringify({ ok: false, error: "app.project.setProxyEnabled(" + enabled + ") failed: " + e.toString() });
89
+ }
90
+
91
+ var readBack = null;
92
+ try {
93
+ readBack = app.project.isProxyEnabled();
94
+ } catch (e) {
95
+ readBack = null;
96
+ }
97
+
98
+ return JSON.stringify({
99
+ ok: true,
100
+ result: {
101
+ action: args.action,
102
+ requestedEnabled: enabled,
103
+ proxiesEnabled: readBack,
104
+ verified: readBack === null ? null : readBack === enabled
105
+ }
106
+ });
107
+ }
108
+
109
+ // action === "attach"
110
+ var hasNodeId = typeof args.nodeId === "string" && args.nodeId.length > 0;
111
+ var hasName = typeof args.name === "string" && args.name.length > 0;
112
+ if (!hasNodeId && !hasName) {
113
+ return JSON.stringify({ ok: false, error: "either nodeId or name is required to address the project item for \"attach\"" });
114
+ }
115
+ if (!args.proxyPath || typeof args.proxyPath !== "string") {
116
+ return JSON.stringify({ ok: false, error: "proxyPath is required for \"attach\"" });
117
+ }
118
+
119
+ var proxyFile = new File(args.proxyPath);
120
+ if (!proxyFile.exists) {
121
+ return JSON.stringify({ ok: false, error: "proxy file not found: " + args.proxyPath });
122
+ }
123
+
124
+ var item = ppbFindItemManageProxies_resolve({
125
+ nodeId: hasNodeId ? args.nodeId : null,
126
+ name: hasNodeId ? null : args.name
127
+ });
128
+ if (!item) {
129
+ return JSON.stringify({ ok: false, error: "no project item found matching the given nodeId/name" });
130
+ }
131
+
132
+ var isHiRes = args.isHiRes === true;
133
+
134
+ var attachResult = null;
135
+ try {
136
+ attachResult = item.attachProxy(args.proxyPath, isHiRes ? 1 : 0);
137
+ } catch (e) {
138
+ return JSON.stringify({ ok: false, error: "item.attachProxy() failed: " + e.toString() });
139
+ }
140
+
141
+ // attachProxy()'s own return value isn't necessarily trustworthy (same
142
+ // lesson as exportFramePNG/createSubClip elsewhere in this panel) —
143
+ // confirm via whatever read-back API exists on this build instead.
144
+ var hasProxyAfter = null;
145
+ try { hasProxyAfter = item.hasProxy(); } catch (e) { hasProxyAfter = null; }
146
+ var proxyPathAfter = null;
147
+ try { proxyPathAfter = item.getProxyPath(); } catch (e) { proxyPathAfter = null; }
148
+
149
+ var verified = null;
150
+ if (hasProxyAfter !== null) {
151
+ verified = hasProxyAfter === true;
152
+ } else if (proxyPathAfter !== null) {
153
+ verified = proxyPathAfter === args.proxyPath;
154
+ }
155
+
156
+ return JSON.stringify({
157
+ ok: true,
158
+ result: {
159
+ action: "attach",
160
+ item: item.name || null,
161
+ nodeId: item.nodeId || null,
162
+ proxyPath: args.proxyPath,
163
+ isHiRes: isHiRes,
164
+ attachReturnValue: attachResult,
165
+ hasProxyAfter: hasProxyAfter,
166
+ proxyPathAfter: proxyPathAfter,
167
+ verified: verified,
168
+ note: verified === null
169
+ ? "attachProxy() did not throw, but neither hasProxy() nor getProxyPath() is available on this build to confirm — treat as unconfirmed"
170
+ : undefined
171
+ }
172
+ });
173
+ } catch (e) {
174
+ return JSON.stringify({ ok: false, error: e.toString() });
175
+ }
176
+ }
@@ -0,0 +1,141 @@
1
+ // Command: match-frame → ppb_matchFrame
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // TICKS_PER_SECOND, timeValueToSeconds, ...) are already defined there.
5
+ //
6
+ // Ported from leancoderkavy/premiere-pro-mcp's utility.ts match_frame.
7
+ // Finds the clip covering `seconds` (or the sequence's own playhead if
8
+ // omitted) on video track 0 by default, computes the equivalent SOURCE
9
+ // time within that clip's media (offset = timelinePosition - clip.start +
10
+ // clip.inPoint, per the reference's own formula), then attempts to load
11
+ // that source into the Source Monitor via
12
+ // `app.sourceMonitor.openProjectItem(item)` (documented in
13
+ // PREMIERE_API_NOTES.md's "Source monitor 3-point editing" line) — this
14
+ // is the part the reference tool itself never actually does (its handler
15
+ // only computes and returns the numbers); this command goes one step
16
+ // further and attempts the real "load the source frame into the source
17
+ // monitor" behavior implied by the command's name.
18
+ //
19
+ // No confirmed API exists to seek the Source Monitor to an exact offset
20
+ // after opening a clip (only .play(speed)/.getPosition()/.closeClip() are
21
+ // documented) — openProjectItem() itself is reported as
22
+ // sourceMonitorOpened; the offset is reported for the caller to act on
23
+ // (e.g. scrub manually, or once a seek API is confirmed).
24
+ function ppb_matchFrame(argsJson) {
25
+ try {
26
+ var args;
27
+ try {
28
+ args = JSON.parse(argsJson);
29
+ } catch (e) {
30
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
31
+ }
32
+
33
+ if (!app.project) {
34
+ return JSON.stringify({ ok: false, error: "no project open" });
35
+ }
36
+
37
+ var seq = null;
38
+ if (args.sequenceName && typeof args.sequenceName === "string") {
39
+ seq = findSequenceByName(args.sequenceName);
40
+ if (!seq) {
41
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
42
+ }
43
+ } else {
44
+ seq = app.project.activeSequence;
45
+ if (!seq) {
46
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
47
+ }
48
+ }
49
+
50
+ var trackType = args.trackType === "audio" ? "audio" : "video";
51
+ var trackIndex = typeof args.trackIndex === "number" ? args.trackIndex : 0;
52
+ var tracks = trackType === "video" ? seq.videoTracks : seq.audioTracks;
53
+ var numTracks = 0;
54
+ try { numTracks = tracks.numTracks; } catch (e) { numTracks = 0; }
55
+ if (trackIndex >= numTracks) {
56
+ return JSON.stringify({ ok: false, error: "trackIndex " + trackIndex + " is out of range — sequence has " + numTracks + " " + trackType + " track(s)" });
57
+ }
58
+
59
+ var atSeconds;
60
+ if (typeof args.seconds === "number" && !isNaN(args.seconds)) {
61
+ atSeconds = args.seconds;
62
+ } else {
63
+ try {
64
+ atSeconds = seq.getPlayerPosition().seconds;
65
+ } catch (e) {
66
+ return JSON.stringify({ ok: false, error: "seconds was omitted and the playhead position could not be read: " + e.toString() });
67
+ }
68
+ }
69
+ var posTicks = atSeconds * TICKS_PER_SECOND;
70
+
71
+ var track = tracks[trackIndex];
72
+ var found = null;
73
+ var numClips = 0;
74
+ try { numClips = track.clips.numItems; } catch (e) { numClips = 0; }
75
+ for (var c = 0; c < numClips; c++) {
76
+ var clip = track.clips[c];
77
+ var startTicks = null;
78
+ var endTicks = null;
79
+ try { startTicks = Number(clip.start.ticks); } catch (e) { startTicks = null; }
80
+ try { endTicks = Number(clip.end.ticks); } catch (e) { endTicks = null; }
81
+ if (startTicks !== null && endTicks !== null && startTicks <= posTicks && endTicks > posTicks) {
82
+ found = clip;
83
+ break;
84
+ }
85
+ }
86
+
87
+ if (!found) {
88
+ return JSON.stringify({ ok: false, error: "no clip at " + atSeconds + "s on " + trackType + " track " + trackIndex });
89
+ }
90
+
91
+ var clipName = null;
92
+ var clipNodeId = null;
93
+ try { clipName = found.name; } catch (e) { clipName = null; }
94
+ try { clipNodeId = found.nodeId; } catch (e) { clipNodeId = null; }
95
+
96
+ var offsetTicks = null;
97
+ try {
98
+ offsetTicks = posTicks - Number(found.start.ticks) + Number(found.inPoint.ticks);
99
+ } catch (e) {
100
+ offsetTicks = null;
101
+ }
102
+
103
+ var result = {
104
+ sequenceName: seq.name,
105
+ trackType: trackType,
106
+ trackIndex: trackIndex,
107
+ timelineSeconds: atSeconds,
108
+ clipName: clipName,
109
+ clipNodeId: clipNodeId,
110
+ sourceSeconds: offsetTicks !== null ? (offsetTicks / TICKS_PER_SECOND) : null,
111
+ sourceItem: null,
112
+ sourceMediaPath: null,
113
+ sourceMonitorOpened: false,
114
+ sourceMonitorError: null
115
+ };
116
+
117
+ var src = null;
118
+ try { src = found.projectItem; } catch (e) { src = null; }
119
+ if (src) {
120
+ try { result.sourceItem = { name: src.name, nodeId: src.nodeId }; } catch (e) { result.sourceItem = null; }
121
+ try { result.sourceMediaPath = src.getMediaPath(); } catch (e) { result.sourceMediaPath = null; }
122
+
123
+ try {
124
+ if (app.sourceMonitor && typeof app.sourceMonitor.openProjectItem === "function") {
125
+ app.sourceMonitor.openProjectItem(src);
126
+ result.sourceMonitorOpened = true;
127
+ } else {
128
+ result.sourceMonitorError = "app.sourceMonitor.openProjectItem is not available on this build";
129
+ }
130
+ } catch (e) {
131
+ result.sourceMonitorError = e.toString();
132
+ }
133
+ } else {
134
+ result.sourceMonitorError = "clip has no projectItem (source) to open";
135
+ }
136
+
137
+ return JSON.stringify({ ok: true, result: result });
138
+ } catch (e) {
139
+ return JSON.stringify({ ok: false, error: e.toString() });
140
+ }
141
+ }