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,162 @@
1
+ // Command: slide-edit → ppb_slideEdit
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // ensureQEEnabled, activateSequenceForQE, resolveTimelineClip,
5
+ // resolveQeClip, serializeTrackItem, TICKS_PER_SECOND, ...) are already
6
+ // defined there.
7
+ //
8
+ // Slides the addressed clip earlier/later on the timeline WITHOUT
9
+ // changing its own duration or source in/out points — the adjacent
10
+ // clips' out/in points absorb the shift instead. Ported from
11
+ // leancoderkavy's premiere-pro-mcp `slide_edit` tool (advanced.ts:
12
+ // `qeClip.slide(offsetTicksString)`), whose signature is UNCONFIRMED on
13
+ // this build (`slide` is on our own reflect list per QE_DOM_NOTES.md /
14
+ // PREMIERE_API_NOTES.md, but never live-called) — every plausible
15
+ // argument form is tried in turn (ticks string, then a raw seconds
16
+ // number, then a Time object), recording an `attempts` array, and
17
+ // success is judged by an actual before/after shift in the clip's own
18
+ // start time matching the requested offset, never by whether the call
19
+ // merely avoided throwing. Positive offsetSeconds slides later, negative
20
+ // slides earlier.
21
+
22
+ function ppbSlideEdit_offsetForms(offsetSeconds) {
23
+ var ticksString = String(Math.round(offsetSeconds * TICKS_PER_SECOND));
24
+ var timeObj = null;
25
+ try {
26
+ timeObj = new Time();
27
+ timeObj.seconds = offsetSeconds;
28
+ } catch (e) {
29
+ timeObj = null;
30
+ }
31
+ var forms = [
32
+ { label: "ticksString", value: ticksString },
33
+ { label: "seconds", value: offsetSeconds }
34
+ ];
35
+ if (timeObj !== null) {
36
+ forms.push({ label: "TimeObject", value: timeObj });
37
+ }
38
+ return forms;
39
+ }
40
+
41
+ function ppb_slideEdit(argsJson) {
42
+ try {
43
+ var args;
44
+ try {
45
+ args = JSON.parse(argsJson);
46
+ } catch (e) {
47
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
48
+ }
49
+
50
+ if (args.trackType !== "video" && args.trackType !== "audio") {
51
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
52
+ }
53
+ if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
54
+ return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
55
+ }
56
+ if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
57
+ return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
58
+ }
59
+ if (typeof args.offsetSeconds !== "number" || isNaN(args.offsetSeconds) || args.offsetSeconds === 0) {
60
+ return JSON.stringify({ ok: false, error: "offsetSeconds must be a non-zero number" });
61
+ }
62
+
63
+ if (!app.project) {
64
+ return JSON.stringify({ ok: false, error: "no project open" });
65
+ }
66
+
67
+ var seq = null;
68
+ if (args.sequenceName && typeof args.sequenceName === "string") {
69
+ seq = findSequenceByName(args.sequenceName);
70
+ if (!seq) {
71
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
72
+ }
73
+ } else {
74
+ seq = app.project.activeSequence;
75
+ if (!seq) {
76
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
77
+ }
78
+ }
79
+
80
+ var resolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
81
+ if (resolved.error) {
82
+ return JSON.stringify({ ok: false, error: resolved.error });
83
+ }
84
+ var before = serializeTrackItem(resolved.clip, args.trackIndex, args.clipIndex);
85
+
86
+ try {
87
+ ensureQEEnabled();
88
+ activateSequenceForQE(seq);
89
+ } catch (e) {
90
+ return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e.toString() });
91
+ }
92
+ if (typeof qe === "undefined" || !qe.project) {
93
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
94
+ }
95
+
96
+ var qeSeq;
97
+ try {
98
+ qeSeq = qe.project.getActiveSequence();
99
+ } catch (e) {
100
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e.toString() });
101
+ }
102
+ var qeResolved = resolveQeClip(qeSeq, args.trackType, args.trackIndex, args.clipIndex);
103
+ if (qeResolved.error) {
104
+ return JSON.stringify({ ok: false, error: qeResolved.error });
105
+ }
106
+ var qeClip = qeResolved.qeClip;
107
+
108
+ if (typeof qeClip.slide !== "function") {
109
+ return JSON.stringify({ ok: false, error: "qeClip.slide is not available on this Premiere build" });
110
+ }
111
+
112
+ var attempts = [];
113
+ var forms = ppbSlideEdit_offsetForms(args.offsetSeconds);
114
+ var succeeded = false;
115
+ var formUsed = null;
116
+ for (var i = 0; i < forms.length && !succeeded; i++) {
117
+ try {
118
+ qeClip.slide(forms[i].value);
119
+ attempts.push({ form: forms[i].label, success: true });
120
+ succeeded = true;
121
+ formUsed = forms[i].label;
122
+ } catch (e) {
123
+ attempts.push({ form: forms[i].label, success: false, error: e.toString() });
124
+ }
125
+ }
126
+
127
+ if (!succeeded) {
128
+ return JSON.stringify({
129
+ ok: false,
130
+ error: "qeClip.slide() failed with every argument form tried",
131
+ attempts: attempts
132
+ });
133
+ }
134
+
135
+ var afterResolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
136
+ var after = afterResolved.clip ? serializeTrackItem(afterResolved.clip, args.trackIndex, args.clipIndex) : null;
137
+
138
+ var startDelta = (after && before && after.startSeconds !== null && before.startSeconds !== null)
139
+ ? (after.startSeconds - before.startSeconds)
140
+ : null;
141
+
142
+ return JSON.stringify({
143
+ ok: true,
144
+ result: {
145
+ sequenceName: seq.name,
146
+ trackType: args.trackType,
147
+ trackIndex: args.trackIndex,
148
+ clipIndex: args.clipIndex,
149
+ requestedOffsetSeconds: args.offsetSeconds,
150
+ formUsed: formUsed,
151
+ attempts: attempts,
152
+ before: before,
153
+ after: after,
154
+ startSecondsDelta: startDelta,
155
+ verified: startDelta !== null && Math.abs(startDelta - args.offsetSeconds) < 0.5,
156
+ note: "verified compares the clip's own start-time shift against the requested offset within half a second — slide's exact neighbor-absorption semantics are unconfirmed on this build (see PREMIERE_API_NOTES.md)."
157
+ }
158
+ });
159
+ } catch (e) {
160
+ return JSON.stringify({ ok: false, error: e.toString() });
161
+ }
162
+ }
@@ -0,0 +1,167 @@
1
+ // Command: slip-edit → ppb_slipEdit
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // ensureQEEnabled, activateSequenceForQE, resolveTimelineClip,
5
+ // resolveQeClip, serializeTrackItem, TICKS_PER_SECOND, ...) are already
6
+ // defined there.
7
+ //
8
+ // Slips the addressed clip's source in/out points forward/backward
9
+ // WITHOUT moving it on the timeline (its start/end stay fixed; which
10
+ // portion of the source media it shows changes). Ported from
11
+ // leancoderkavy's premiere-pro-mcp `slip_edit` tool (advanced.ts:
12
+ // `qeClip.slip(offsetTicksString)`), whose signature is UNCONFIRMED on
13
+ // this build (`slip` is on our own reflect list per QE_DOM_NOTES.md /
14
+ // PREMIERE_API_NOTES.md, but never live-called) — every plausible
15
+ // argument form is tried in turn (ticks string, then a raw seconds
16
+ // number, then a Time object), recording an `attempts` array, and
17
+ // success is judged by an actual before/after shift in the clip's own
18
+ // inPoint matching the requested offset, never by whether the call
19
+ // merely avoided throwing. Positive offsetSeconds slips forward in the
20
+ // source, negative slips backward.
21
+
22
+ function ppbSlipEdit_offsetForms(offsetSeconds) {
23
+ var ticksString = String(Math.round(offsetSeconds * TICKS_PER_SECOND));
24
+ var timeObj = null;
25
+ try {
26
+ timeObj = new Time();
27
+ timeObj.seconds = offsetSeconds;
28
+ } catch (e) {
29
+ timeObj = null;
30
+ }
31
+ var forms = [
32
+ { label: "ticksString", value: ticksString },
33
+ { label: "seconds", value: offsetSeconds }
34
+ ];
35
+ if (timeObj !== null) {
36
+ forms.push({ label: "TimeObject", value: timeObj });
37
+ }
38
+ return forms;
39
+ }
40
+
41
+ function ppb_slipEdit(argsJson) {
42
+ try {
43
+ var args;
44
+ try {
45
+ args = JSON.parse(argsJson);
46
+ } catch (e) {
47
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
48
+ }
49
+
50
+ if (args.trackType !== "video" && args.trackType !== "audio") {
51
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
52
+ }
53
+ if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
54
+ return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
55
+ }
56
+ if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
57
+ return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
58
+ }
59
+ if (typeof args.offsetSeconds !== "number" || isNaN(args.offsetSeconds) || args.offsetSeconds === 0) {
60
+ return JSON.stringify({ ok: false, error: "offsetSeconds must be a non-zero number" });
61
+ }
62
+
63
+ if (!app.project) {
64
+ return JSON.stringify({ ok: false, error: "no project open" });
65
+ }
66
+
67
+ var seq = null;
68
+ if (args.sequenceName && typeof args.sequenceName === "string") {
69
+ seq = findSequenceByName(args.sequenceName);
70
+ if (!seq) {
71
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
72
+ }
73
+ } else {
74
+ seq = app.project.activeSequence;
75
+ if (!seq) {
76
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
77
+ }
78
+ }
79
+
80
+ var resolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
81
+ if (resolved.error) {
82
+ return JSON.stringify({ ok: false, error: resolved.error });
83
+ }
84
+ var before = serializeTrackItem(resolved.clip, args.trackIndex, args.clipIndex);
85
+
86
+ try {
87
+ ensureQEEnabled();
88
+ activateSequenceForQE(seq);
89
+ } catch (e) {
90
+ return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e.toString() });
91
+ }
92
+ if (typeof qe === "undefined" || !qe.project) {
93
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
94
+ }
95
+
96
+ var qeSeq;
97
+ try {
98
+ qeSeq = qe.project.getActiveSequence();
99
+ } catch (e) {
100
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e.toString() });
101
+ }
102
+ var qeResolved = resolveQeClip(qeSeq, args.trackType, args.trackIndex, args.clipIndex);
103
+ if (qeResolved.error) {
104
+ return JSON.stringify({ ok: false, error: qeResolved.error });
105
+ }
106
+ var qeClip = qeResolved.qeClip;
107
+
108
+ if (typeof qeClip.slip !== "function") {
109
+ return JSON.stringify({ ok: false, error: "qeClip.slip is not available on this Premiere build" });
110
+ }
111
+
112
+ var attempts = [];
113
+ var forms = ppbSlipEdit_offsetForms(args.offsetSeconds);
114
+ var succeeded = false;
115
+ var formUsed = null;
116
+ for (var i = 0; i < forms.length && !succeeded; i++) {
117
+ try {
118
+ qeClip.slip(forms[i].value);
119
+ attempts.push({ form: forms[i].label, success: true });
120
+ succeeded = true;
121
+ formUsed = forms[i].label;
122
+ } catch (e) {
123
+ attempts.push({ form: forms[i].label, success: false, error: e.toString() });
124
+ }
125
+ }
126
+
127
+ if (!succeeded) {
128
+ return JSON.stringify({
129
+ ok: false,
130
+ error: "qeClip.slip() failed with every argument form tried",
131
+ attempts: attempts
132
+ });
133
+ }
134
+
135
+ var afterResolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
136
+ var after = afterResolved.clip ? serializeTrackItem(afterResolved.clip, args.trackIndex, args.clipIndex) : null;
137
+
138
+ var inPointDelta = (after && before && after.inPointSeconds !== null && before.inPointSeconds !== null)
139
+ ? (after.inPointSeconds - before.inPointSeconds)
140
+ : null;
141
+ var startDelta = (after && before && after.startSeconds !== null && before.startSeconds !== null)
142
+ ? (after.startSeconds - before.startSeconds)
143
+ : null;
144
+
145
+ return JSON.stringify({
146
+ ok: true,
147
+ result: {
148
+ sequenceName: seq.name,
149
+ trackType: args.trackType,
150
+ trackIndex: args.trackIndex,
151
+ clipIndex: args.clipIndex,
152
+ requestedOffsetSeconds: args.offsetSeconds,
153
+ formUsed: formUsed,
154
+ attempts: attempts,
155
+ before: before,
156
+ after: after,
157
+ inPointSecondsDelta: inPointDelta,
158
+ startSecondsDelta: startDelta,
159
+ verified: inPointDelta !== null && Math.abs(inPointDelta - args.offsetSeconds) < 0.5 &&
160
+ (startDelta === null || Math.abs(startDelta) < 0.5),
161
+ note: "verified checks that inPoint shifted by roughly the requested offset while start stayed roughly fixed — slip's exact semantics are unconfirmed on this build (see PREMIERE_API_NOTES.md)."
162
+ }
163
+ });
164
+ } catch (e) {
165
+ return JSON.stringify({ ok: false, error: e.toString() });
166
+ }
167
+ }
@@ -0,0 +1,144 @@
1
+
2
+ // seconds -> "HH:MM:SS:FF" — the razor argument form PROVEN working on
3
+ // this build (remove-track-intervals live-validated it); the ticksString
4
+ // form silently no-ops (live-tested 2026-07-17).
5
+ function ppbSplitClip_secondsToQeTimecode(seconds, fps) {
6
+ var totalFrames = Math.round(seconds * fps);
7
+ var ff = totalFrames % Math.round(fps);
8
+ var totalSeconds = Math.floor(totalFrames / Math.round(fps));
9
+ var ss = totalSeconds % 60;
10
+ var totalMinutes = Math.floor(totalSeconds / 60);
11
+ var mm = totalMinutes % 60;
12
+ var hh = Math.floor(totalMinutes / 60);
13
+ function pad2(n) { return (n < 10 ? "0" : "") + n; }
14
+ return pad2(hh) + ":" + pad2(mm) + ":" + pad2(ss) + ":" + pad2(ff);
15
+ }
16
+ // Command: split-clip → ppb_splitClip
17
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
18
+ // same global ExtendScript context — shared helpers (findSequenceByName,
19
+ // ensureQEEnabled, activateSequenceForQE, secondsToTicksString, ...) are
20
+ // already defined there.
21
+ //
22
+ // Splits (razors) whichever clip covers a given SEQUENCE-TIME position on
23
+ // one track, via the QE DOM's qeTrack.razor(ticksString) —
24
+ // PREMIERE_API_NOTES.md: "Split/razor: QE only ... Standard-DOM
25
+ // 'fallback' (truncating clip.end) is destructive — don't." Addressed by
26
+ // trackType/trackIndex only (not clipIndex) since a razor cut targets a
27
+ // TIME, not a specific clip index — matches leancoderkavy's
28
+ // premiere-pro-mcp split_clip tool. Activates the resolved sequence
29
+ // first (QE DOM only ever operates on the active sequence tab), same
30
+ // pattern as remove-track-intervals/get-qe-clip-info.
31
+ //
32
+ // MUTATION RULE: verified via the STANDARD-DOM track's clips.numItems
33
+ // increasing by exactly one (never razor()'s own return value).
34
+
35
+ function ppb_splitClip(argsJson) {
36
+ try {
37
+ var args;
38
+ try {
39
+ args = JSON.parse(argsJson);
40
+ } catch (e) {
41
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
42
+ }
43
+
44
+ if (args.trackType !== "video" && args.trackType !== "audio") {
45
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
46
+ }
47
+ if (typeof args.trackIndex !== "number") {
48
+ return JSON.stringify({ ok: false, error: "trackIndex is required" });
49
+ }
50
+ if (typeof args.seconds !== "number") {
51
+ return JSON.stringify({ ok: false, error: "seconds is required" });
52
+ }
53
+
54
+ if (!app.project) {
55
+ return JSON.stringify({ ok: false, error: "no project open" });
56
+ }
57
+
58
+ var seq = null;
59
+ if (args.sequenceName && typeof args.sequenceName === "string") {
60
+ seq = findSequenceByName(args.sequenceName);
61
+ if (!seq) {
62
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
63
+ }
64
+ } else {
65
+ seq = app.project.activeSequence;
66
+ if (!seq) {
67
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
68
+ }
69
+ }
70
+
71
+ var stdTrackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
72
+ var numStdTracks;
73
+ try { numStdTracks = stdTrackCollection.numTracks; } catch (e2) { numStdTracks = 0; }
74
+ if (args.trackIndex >= numStdTracks) {
75
+ return JSON.stringify({ ok: false, error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numStdTracks + " " + args.trackType + " track(s)" });
76
+ }
77
+ var stdTrack = stdTrackCollection[args.trackIndex];
78
+ var clipCountBefore = null;
79
+ try { clipCountBefore = stdTrack.clips.numItems; } catch (e3) { clipCountBefore = null; }
80
+
81
+ try {
82
+ ensureQEEnabled();
83
+ activateSequenceForQE(seq);
84
+ } catch (e4) {
85
+ return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e4.toString() });
86
+ }
87
+ if (typeof qe === "undefined" || !qe.project) {
88
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
89
+ }
90
+
91
+ var qeSeq;
92
+ try {
93
+ qeSeq = qe.project.getActiveSequence();
94
+ } catch (e5) {
95
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e5.toString() });
96
+ }
97
+ if (!qeSeq) {
98
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() returned nothing after activating the sequence" });
99
+ }
100
+
101
+ var qeTrack;
102
+ try {
103
+ qeTrack = args.trackType === "video" ? qeSeq.getVideoTrackAt(args.trackIndex) : qeSeq.getAudioTrackAt(args.trackIndex);
104
+ } catch (e6) {
105
+ return JSON.stringify({ ok: false, error: "QE track lookup failed: " + e6.toString() });
106
+ }
107
+ if (!qeTrack) {
108
+ return JSON.stringify({ ok: false, error: "QE track not found at index " + args.trackIndex });
109
+ }
110
+
111
+ var ticksString = secondsToTicksString(args.seconds);
112
+ try {
113
+ var fps2 = getSequenceFps(seq);
114
+ var qeTimecode2 = ppbSplitClip_secondsToQeTimecode(args.seconds, fps2);
115
+ try {
116
+ qeTrack.razor(qeTimecode2);
117
+ } catch (eTc) {
118
+ qeTrack.razor(ticksString);
119
+ }
120
+ } catch (e7) {
121
+ return JSON.stringify({ ok: false, error: "qeTrack.razor() failed: " + e7.toString() });
122
+ }
123
+
124
+ var clipCountAfter = null;
125
+ try { clipCountAfter = stdTrack.clips.numItems; } catch (e8) { clipCountAfter = null; }
126
+
127
+ var verified = clipCountBefore !== null && clipCountAfter !== null && clipCountAfter === clipCountBefore + 1;
128
+
129
+ return JSON.stringify({
130
+ ok: true,
131
+ result: {
132
+ sequenceName: seq.name,
133
+ trackType: args.trackType,
134
+ trackIndex: args.trackIndex,
135
+ seconds: args.seconds,
136
+ clipCountBefore: clipCountBefore,
137
+ clipCountAfter: clipCountAfter,
138
+ verified: verified
139
+ }
140
+ });
141
+ } catch (e) {
142
+ return JSON.stringify({ ok: false, error: e.toString() });
143
+ }
144
+ }
@@ -0,0 +1,139 @@
1
+ // Command: stabilize-clip → ppb_stabilizeClip
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // ensureQEEnabled, activateSequenceForQE, resolveTimelineClip,
5
+ // resolveQeClip, serializeClipComponents, findQeVideoEffectByName,
6
+ // findClipComponent, setComponentProperty, ...) are already defined there.
7
+ //
8
+ // Applies Warp Stabilizer via the standard QE dance (getVideoEffectByName +
9
+ // addVideoEffect), verified by clip.components.numItems increasing by 1,
10
+ // then optionally sets "Smoothness" (number) and/or "Method" (string enum —
11
+ // "Subspace Warp"/"Position"/"Position, Scale, Rotation" per the reference
12
+ // tool) via the shared setComponentProperty helper. Warp Stabilizer analysis
13
+ // itself runs asynchronously inside Premiere after being applied — this
14
+ // command does not wait for or report analysis completion.
15
+ function ppb_stabilizeClip(argsJson) {
16
+ try {
17
+ var args;
18
+ try {
19
+ args = JSON.parse(argsJson);
20
+ } catch (e) {
21
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
22
+ }
23
+
24
+ if (args.trackType !== "video") {
25
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" — Warp Stabilizer is a video effect" });
26
+ }
27
+ if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
28
+ return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
29
+ }
30
+ if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
31
+ return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
32
+ }
33
+ if (args.smoothness !== undefined && typeof args.smoothness !== "number") {
34
+ return JSON.stringify({ ok: false, error: "smoothness must be a number if given" });
35
+ }
36
+ if (args.method !== undefined && typeof args.method !== "string") {
37
+ return JSON.stringify({ ok: false, error: "method must be a string if given" });
38
+ }
39
+
40
+ if (!app.project) {
41
+ return JSON.stringify({ ok: false, error: "no project open" });
42
+ }
43
+
44
+ var seq = null;
45
+ if (args.sequenceName && typeof args.sequenceName === "string") {
46
+ seq = findSequenceByName(args.sequenceName);
47
+ if (!seq) {
48
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
49
+ }
50
+ } else {
51
+ seq = app.project.activeSequence;
52
+ if (!seq) {
53
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
54
+ }
55
+ }
56
+
57
+ var resolvedClip = resolveTimelineClip(seq, "video", args.trackIndex, args.clipIndex);
58
+ if (resolvedClip.error) {
59
+ return JSON.stringify({ ok: false, error: resolvedClip.error });
60
+ }
61
+ var clip = resolvedClip.clip;
62
+ var clipName = null;
63
+ try { clipName = clip.name; } catch (e) { clipName = null; }
64
+
65
+ var previousComponents = serializeClipComponents(clip);
66
+
67
+ try {
68
+ ensureQEEnabled();
69
+ activateSequenceForQE(seq);
70
+ } catch (e) {
71
+ return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e.toString() });
72
+ }
73
+ if (typeof qe === "undefined" || !qe.project) {
74
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
75
+ }
76
+
77
+ var qeSeq;
78
+ try {
79
+ qeSeq = qe.project.getActiveSequence();
80
+ } catch (e) {
81
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e.toString() });
82
+ }
83
+
84
+ var qeResolved = resolveQeClip(qeSeq, "video", args.trackIndex, args.clipIndex);
85
+ if (qeResolved.error) {
86
+ return JSON.stringify({ ok: false, error: qeResolved.error });
87
+ }
88
+
89
+ var fx = findQeVideoEffectByName("Warp Stabilizer");
90
+ if (!fx) {
91
+ return JSON.stringify({ ok: false, error: "Warp Stabilizer effect not found in this Premiere install's QE effect catalog" });
92
+ }
93
+
94
+ try {
95
+ qeResolved.qeClip.addVideoEffect(fx);
96
+ } catch (e) {
97
+ return JSON.stringify({ ok: false, error: "qeClip.addVideoEffect(Warp Stabilizer) failed: " + e.toString() });
98
+ }
99
+
100
+ var newComponents = serializeClipComponents(clip);
101
+ var componentVerified = newComponents.length === previousComponents.length + 1;
102
+
103
+ var changes = {};
104
+ if (componentVerified) {
105
+ var warpComp = findClipComponent(clip, null, ["Warp Stabilizer"]);
106
+ if (warpComp) {
107
+ if (typeof args.smoothness === "number") {
108
+ var smoothResult = setComponentProperty(warpComp, ["Smoothness"], args.smoothness);
109
+ changes.smoothness = smoothResult.found ? smoothResult : { found: false };
110
+ }
111
+ if (typeof args.method === "string") {
112
+ var methodResult = setComponentProperty(warpComp, ["Method"], args.method);
113
+ changes.method = methodResult.found ? methodResult : { found: false };
114
+ }
115
+ } else if (typeof args.smoothness === "number" || typeof args.method === "string") {
116
+ changes.error = "Warp Stabilizer was applied but could not be re-found on the standard-DOM clip to set properties";
117
+ }
118
+ }
119
+
120
+ return JSON.stringify({
121
+ ok: true,
122
+ result: {
123
+ sequenceName: seq.name,
124
+ trackType: "video",
125
+ trackIndex: args.trackIndex,
126
+ clipIndex: args.clipIndex,
127
+ clipName: clipName,
128
+ verified: componentVerified,
129
+ changes: changes,
130
+ previousComponentCount: previousComponents.length,
131
+ newComponentCount: newComponents.length,
132
+ previousComponents: previousComponents,
133
+ newComponents: newComponents
134
+ }
135
+ });
136
+ } catch (e) {
137
+ return JSON.stringify({ ok: false, error: e.toString() });
138
+ }
139
+ }
@@ -0,0 +1,23 @@
1
+ // Command: stop-playback → ppb_stopPlayback
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
+ // Ported from leancoderkavy/premiere-pro-mcp's playback.ts stop_playback.
7
+ // QE DOM only (qe.stopPlayback()) — inherently active-sequence-only, same
8
+ // as play-timeline: no sequenceName override.
9
+ function ppb_stopPlayback(argsJson) {
10
+ try {
11
+ ensureQEEnabled();
12
+
13
+ try {
14
+ qe.stopPlayback();
15
+ } catch (e) {
16
+ return JSON.stringify({ ok: false, error: "could not stop playback: " + e.toString() });
17
+ }
18
+
19
+ return JSON.stringify({ ok: true, result: { stopped: true } });
20
+ } catch (e) {
21
+ return JSON.stringify({ ok: false, error: e.toString() });
22
+ }
23
+ }