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,192 @@
1
+ // Command: remove-keyframe → ppb_removeKeyframe
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // findClipComponent, findComponentProperty, timeValueToSeconds,
5
+ // keyTimeToSeconds, tryTimeForms, getSequenceFps, ...) are already defined
6
+ // there.
7
+ //
8
+ // Standard-DOM mutation. Ported from leancoderkavy's premiere-pro-mcp
9
+ // `remove_keyframe` tool (keyframes.ts), addressed here by
10
+ // trackType/trackIndex/clipIndex + componentName/propertyName. `seconds`
11
+ // is clip-relative, offset by clip.start to sequence time. Tolerance is
12
+ // fixed at HALF A FRAME (0.5 / sequence fps) either side of the requested
13
+ // time, per the task spec — this is the cleanup path for add-keyframe
14
+ // mistakes (undo is non-functional on this build), so it first tries to
15
+ // locate an EXISTING key within tolerance via getKeys() (removing that
16
+ // exact key object, most likely to succeed), falling back to constructing
17
+ // a fresh time argument at the requested position via tryTimeForms() if no
18
+ // existing key matched or getKeys() itself is unavailable. Verified via a
19
+ // getKeys() COUNT drop, not by confirming which key vanished.
20
+ function ppb_removeKeyframe(argsJson) {
21
+ try {
22
+ var args;
23
+ try {
24
+ args = JSON.parse(argsJson);
25
+ } catch (e) {
26
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
27
+ }
28
+
29
+ if (args.trackType !== "video" && args.trackType !== "audio") {
30
+ return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
31
+ }
32
+ if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
33
+ return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
34
+ }
35
+ if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
36
+ return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
37
+ }
38
+ if (typeof args.componentName !== "string" || !args.componentName) {
39
+ return JSON.stringify({ ok: false, error: "componentName is required" });
40
+ }
41
+ if (typeof args.propertyName !== "string" || !args.propertyName) {
42
+ return JSON.stringify({ ok: false, error: "propertyName is required" });
43
+ }
44
+ if (typeof args.seconds !== "number") {
45
+ return JSON.stringify({ ok: false, error: "seconds must be a number (clip-relative)" });
46
+ }
47
+
48
+ if (!app.project) {
49
+ return JSON.stringify({ ok: false, error: "no project open" });
50
+ }
51
+
52
+ var seq = null;
53
+ if (args.sequenceName && typeof args.sequenceName === "string") {
54
+ seq = findSequenceByName(args.sequenceName);
55
+ if (!seq) {
56
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
57
+ }
58
+ } else {
59
+ seq = app.project.activeSequence;
60
+ if (!seq) {
61
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
62
+ }
63
+ }
64
+
65
+ var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
66
+ var numTracks = trackCollection.numTracks;
67
+ if (args.trackIndex >= numTracks) {
68
+ return JSON.stringify({
69
+ ok: false,
70
+ error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
71
+ });
72
+ }
73
+
74
+ var track = trackCollection[args.trackIndex];
75
+ var numClips = track.clips.numItems;
76
+ if (args.clipIndex >= numClips) {
77
+ return JSON.stringify({
78
+ ok: false,
79
+ error: "clipIndex " + args.clipIndex + " is out of range — track " + args.trackIndex + " has " + numClips + " clip(s)"
80
+ });
81
+ }
82
+
83
+ var clip = track.clips[args.clipIndex];
84
+ var clipName = null;
85
+ try { clipName = clip.name; } catch (e) { clipName = null; }
86
+
87
+ var clipStartSeconds = 0;
88
+ try { clipStartSeconds = timeValueToSeconds(clip.start) || 0; } catch (e) { clipStartSeconds = 0; }
89
+
90
+ var comp = findClipComponent(clip, [args.componentName], [args.componentName]);
91
+ if (!comp) {
92
+ return JSON.stringify({
93
+ ok: false,
94
+ error: "component \"" + args.componentName + "\" not found on clip (matched against matchName and displayName)"
95
+ });
96
+ }
97
+ var compDisplayName = null;
98
+ try { compDisplayName = comp.displayName; } catch (e) { compDisplayName = null; }
99
+
100
+ var prop = findComponentProperty(comp, [args.propertyName]);
101
+ if (!prop) {
102
+ return JSON.stringify({
103
+ ok: false,
104
+ error: "property \"" + args.propertyName + "\" not found on component \"" + compDisplayName + "\""
105
+ });
106
+ }
107
+
108
+ var fps = 30;
109
+ try { fps = getSequenceFps(seq) || 30; } catch (e) { fps = 30; }
110
+ var toleranceSeconds = 0.5 / fps;
111
+
112
+ var sequenceSeconds = clipStartSeconds + args.seconds;
113
+
114
+ var keyCountBefore = 0;
115
+ var rawKeys = null;
116
+ try {
117
+ rawKeys = prop.getKeys();
118
+ keyCountBefore = rawKeys ? rawKeys.length : 0;
119
+ } catch (e) {
120
+ keyCountBefore = null;
121
+ }
122
+
123
+ var matchedKey = null;
124
+ var matchedSeconds = null;
125
+ if (rawKeys) {
126
+ for (var i = 0; i < rawKeys.length; i++) {
127
+ var ks = null;
128
+ try { ks = keyTimeToSeconds(rawKeys[i]); } catch (e1) { ks = null; }
129
+ if (ks !== null && Math.abs(ks - sequenceSeconds) <= toleranceSeconds) {
130
+ matchedKey = rawKeys[i];
131
+ matchedSeconds = ks;
132
+ break;
133
+ }
134
+ }
135
+ }
136
+
137
+ var removeAttempts = [];
138
+ var removed = false;
139
+
140
+ if (matchedKey !== null) {
141
+ try {
142
+ prop.removeKey(matchedKey);
143
+ removeAttempts.push({ form: "existingKeyObject", success: true });
144
+ removed = true;
145
+ } catch (e2) {
146
+ removeAttempts.push({ form: "existingKeyObject", success: false, error: e2.toString() });
147
+ }
148
+ }
149
+
150
+ if (!removed) {
151
+ var tf = tryTimeForms(sequenceSeconds, function (t) {
152
+ prop.removeKey(t);
153
+ });
154
+ removeAttempts = removeAttempts.concat(tf.attempts);
155
+ removed = tf.success;
156
+ }
157
+
158
+ var keyCountAfter = 0;
159
+ try {
160
+ var keysAfter = prop.getKeys();
161
+ keyCountAfter = keysAfter ? keysAfter.length : 0;
162
+ } catch (e3) {
163
+ keyCountAfter = null;
164
+ }
165
+
166
+ var verified = (keyCountBefore !== null && keyCountAfter !== null && keyCountAfter === keyCountBefore - 1);
167
+
168
+ return JSON.stringify({
169
+ ok: true,
170
+ result: {
171
+ sequenceName: seq.name,
172
+ trackType: args.trackType,
173
+ trackIndex: args.trackIndex,
174
+ clipIndex: args.clipIndex,
175
+ clipName: clipName,
176
+ componentName: compDisplayName,
177
+ propertyName: args.propertyName,
178
+ seconds: args.seconds,
179
+ sequenceSeconds: sequenceSeconds,
180
+ toleranceSeconds: toleranceSeconds,
181
+ matchedExistingKey: matchedKey !== null,
182
+ matchedSeconds: matchedSeconds,
183
+ removeAttempts: removeAttempts,
184
+ keyCountBefore: keyCountBefore,
185
+ keyCountAfter: keyCountAfter,
186
+ verified: verified
187
+ }
188
+ });
189
+ } catch (e) {
190
+ return JSON.stringify({ ok: false, error: e.toString() });
191
+ }
192
+ }
@@ -0,0 +1,126 @@
1
+ // Command: remove-selected-clips → ppb_removeSelectedClips
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (findSequenceByName,
4
+ // serializeTrackItem, ...) are already defined there.
5
+ //
6
+ // Ported from leancoderkavy/premiere-pro-mcp's track-targeting.ts
7
+ // remove_selected_clips. Removes every currently-selected clip (video+
8
+ // audio) via clip.remove(rippleBool, /*alignToVideo*/true). Selected
9
+ // clips are collected BACKWARDS per track (highest clipIndex first) so
10
+ // that removing one clip never invalidates the still-pending indices of
11
+ // clips before it on the same track — a ripple=true removal shifts every
12
+ // later clip on that track.
13
+ //
14
+ // Destructive: removed clips cannot be restored (undo is non-functional
15
+ // on this build per README.md) — verify on a duplicate/throwaway
16
+ // sequence before running against real footage.
17
+ //
18
+ // Verification: total clip count across all tracks, before/after, plus a
19
+ // per-clip removed/failed breakdown (never trusting remove()'s own return
20
+ // value — same rule as every other mutation command in this panel).
21
+ function ppb_countAllClips(seq) {
22
+ var total = 0;
23
+ try {
24
+ for (var v = 0; v < seq.videoTracks.numTracks; v++) {
25
+ total += seq.videoTracks[v].clips.numItems;
26
+ }
27
+ } catch (e) {
28
+ // best-effort
29
+ }
30
+ try {
31
+ for (var a = 0; a < seq.audioTracks.numTracks; a++) {
32
+ total += seq.audioTracks[a].clips.numItems;
33
+ }
34
+ } catch (e) {
35
+ // best-effort
36
+ }
37
+ return total;
38
+ }
39
+
40
+ function ppb_removeSelectedClips(argsJson) {
41
+ try {
42
+ var args;
43
+ try {
44
+ args = JSON.parse(argsJson);
45
+ } catch (e) {
46
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
47
+ }
48
+
49
+ if (!app.project) {
50
+ return JSON.stringify({ ok: false, error: "no project open" });
51
+ }
52
+
53
+ var seq = null;
54
+ if (args.sequenceName && typeof args.sequenceName === "string") {
55
+ seq = findSequenceByName(args.sequenceName);
56
+ if (!seq) {
57
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
58
+ }
59
+ } else {
60
+ seq = app.project.activeSequence;
61
+ if (!seq) {
62
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
63
+ }
64
+ }
65
+
66
+ var ripple = args.ripple === true;
67
+
68
+ var toRemove = [];
69
+ function collectSelectedBackwards(tracks, trackType) {
70
+ for (var t = 0; t < tracks.numTracks; t++) {
71
+ for (var c = tracks[t].clips.numItems - 1; c >= 0; c--) {
72
+ var clip = tracks[t].clips[c];
73
+ var isSel = false;
74
+ try { isSel = clip.isSelected(); } catch (e) { isSel = false; }
75
+ if (isSel) {
76
+ var name = null;
77
+ try { name = clip.name; } catch (e2) { name = null; }
78
+ toRemove.push({ clip: clip, trackType: trackType, trackIndex: t, clipIndex: c, name: name });
79
+ }
80
+ }
81
+ }
82
+ }
83
+ collectSelectedBackwards(seq.videoTracks, "video");
84
+ collectSelectedBackwards(seq.audioTracks, "audio");
85
+
86
+ var countBefore = ppb_countAllClips(seq);
87
+
88
+ var results = [];
89
+ var removedCount = 0;
90
+ for (var i = 0; i < toRemove.length; i++) {
91
+ var entry = toRemove[i];
92
+ var removeError = null;
93
+ try {
94
+ entry.clip.remove(ripple, true);
95
+ removedCount++;
96
+ } catch (e) {
97
+ removeError = e.toString();
98
+ }
99
+ results.push({
100
+ trackType: entry.trackType,
101
+ trackIndex: entry.trackIndex,
102
+ clipIndex: entry.clipIndex,
103
+ name: entry.name,
104
+ error: removeError
105
+ });
106
+ }
107
+
108
+ var countAfter = ppb_countAllClips(seq);
109
+
110
+ return JSON.stringify({
111
+ ok: true,
112
+ result: {
113
+ sequenceName: seq.name,
114
+ ripple: ripple,
115
+ selectedCount: toRemove.length,
116
+ removedCount: removedCount,
117
+ countBefore: countBefore,
118
+ countAfter: countAfter,
119
+ verified: countAfter === countBefore - removedCount,
120
+ results: results
121
+ }
122
+ });
123
+ } catch (e) {
124
+ return JSON.stringify({ ok: false, error: e.toString() });
125
+ }
126
+ }
@@ -0,0 +1,254 @@
1
+ // Command: remove-track-intervals → ppb_removeTrackIntervals
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (ensureQEEnabled,
4
+ // findSequenceByName, getSequenceFps, timecodeToSeconds, ...) are already
5
+ // defined there.
6
+ //
7
+ // Ripple-deletes a list of time intervals from an audio track (and,
8
+ // optionally, from one or more linked video tracks so they stay in
9
+ // sync), via the QE DOM's razor() + a rippleDelete()/remove() fallback
10
+ // whose success is judged by an actual numItems drop, not either call's
11
+ // return value (both are unreliable in practice on this Premiere
12
+ // version). Adapted from a proven implementation in a sibling project.
13
+ //
14
+ // QE DOM operates on qe.project.getActiveSequence() only — whichever
15
+ // sequence tab is frontmost — so this command makes the resolved
16
+ // sequence the active one first (app.project.activeSequence = seq)
17
+ // rather than erroring if it isn't already.
18
+
19
+ function toQeTimecode(timecode) {
20
+ // remove_pauses.py's frames_to_timecode() emits total elapsed minutes with
21
+ // no 60-minute cap (e.g. 75 minutes in prints as "75:03:12"), so MM here
22
+ // can exceed 59 for any sequence over an hour. QE razor() wants a genuine
23
+ // "HH:MM:SS:FF" with minutes in [0,59], so carry the excess into hours
24
+ // rather than assuming MM is always sub-hour.
25
+ var parts = timecode.split(":");
26
+ var totalMinutes = parseInt(parts[0], 10);
27
+ var seconds = parts[1];
28
+ var frames = parts[2];
29
+ var hours = Math.floor(totalMinutes / 60);
30
+ var minutes = totalMinutes % 60;
31
+ function pad2(n) {
32
+ return (n < 10 ? "0" : "") + n;
33
+ }
34
+ return pad2(hours) + ":" + pad2(minutes) + ":" + seconds + ":" + frames;
35
+ }
36
+
37
+ function findAndRemoveInRange(qeTrack, startSeconds, endSeconds, tolerance, warnings, trackLabel) {
38
+ var matches = [];
39
+ for (var k = 0; k < qeTrack.numItems; k++) {
40
+ var item = qeTrack.getItemAt(k);
41
+ // QE track items include "Empty" gap placeholders alongside real
42
+ // "Clip" items (confirmed earlier this session, see QE_DOM_NOTES.md).
43
+ // Razoring both boundaries of a pause can leave an Empty item bounded
44
+ // by the same tolerance window as the real Clip we actually want to
45
+ // remove — attempting to remove an Empty item is a harmless no-op
46
+ // (there's nothing there), but it was previously misreported as a
47
+ // removal failure. Skip non-Clip items so warnings only fire for
48
+ // genuine failures.
49
+ if (item.type !== "Clip") {
50
+ continue;
51
+ }
52
+ var itemStart = Number(item.start.ticks) / TICKS_PER_SECOND;
53
+ var itemEnd = Number(item.end.ticks) / TICKS_PER_SECOND;
54
+ if (itemStart > startSeconds - tolerance && itemEnd < endSeconds + tolerance) {
55
+ matches.push(item);
56
+ }
57
+ }
58
+
59
+ var removed = 0;
60
+ for (var m = 0; m < matches.length; m++) {
61
+ var target = matches[m];
62
+ var succeeded = false;
63
+ var itemCountBefore = qeTrack.numItems;
64
+
65
+ if (typeof target.rippleDelete === "function") {
66
+ try {
67
+ target.rippleDelete();
68
+ } catch (e) {
69
+ // fall through to the numItems check below regardless
70
+ }
71
+ succeeded = qeTrack.numItems < itemCountBefore;
72
+ }
73
+
74
+ if (!succeeded && typeof target.remove === "function") {
75
+ // QE clip.remove()'s two boolean params are undocumented (roughly
76
+ // ripple/alignToVideo-shaped, per Premiere's standard-DOM equivalent) —
77
+ // try plausible combinations and judge success by numItems, not by
78
+ // assuming what either flag means.
79
+ var attempts = [[true, false], [true, true], [false, true], [false, false]];
80
+ for (var a = 0; a < attempts.length && !succeeded; a++) {
81
+ var countBeforeAttempt = qeTrack.numItems;
82
+ try {
83
+ target.remove(attempts[a][0], attempts[a][1]);
84
+ } catch (e) {
85
+ // fall through to the numItems check below regardless
86
+ }
87
+ succeeded = qeTrack.numItems < countBeforeAttempt;
88
+ }
89
+ }
90
+
91
+ if (succeeded) {
92
+ removed++;
93
+ }
94
+ }
95
+
96
+ if (removed < matches.length) {
97
+ warnings.push(
98
+ trackLabel + ": " + (matches.length - removed) + " of " + matches.length +
99
+ " segment(s) in range could not be removed (rippleDelete/remove all reported no change)"
100
+ );
101
+ }
102
+
103
+ return removed;
104
+ }
105
+
106
+ function ppb_removeTrackIntervals(argsJson) {
107
+ try {
108
+ var args;
109
+ try {
110
+ args = JSON.parse(argsJson);
111
+ } catch (e) {
112
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
113
+ }
114
+
115
+ if (typeof args.audioTrackIndex !== "number" || args.audioTrackIndex < 0 || Math.floor(args.audioTrackIndex) !== args.audioTrackIndex) {
116
+ return JSON.stringify({ ok: false, error: "audioTrackIndex must be a non-negative integer" });
117
+ }
118
+ var videoTrackIndices = args.videoTrackIndices || [];
119
+ if (!(videoTrackIndices instanceof Array)) {
120
+ return JSON.stringify({ ok: false, error: "videoTrackIndices must be an array" });
121
+ }
122
+ for (var vi = 0; vi < videoTrackIndices.length; vi++) {
123
+ var vIdx = videoTrackIndices[vi];
124
+ if (typeof vIdx !== "number" || vIdx < 0 || Math.floor(vIdx) !== vIdx) {
125
+ return JSON.stringify({ ok: false, error: "videoTrackIndices must all be non-negative integers" });
126
+ }
127
+ }
128
+ if (!(args.intervals instanceof Array) || args.intervals.length === 0) {
129
+ return JSON.stringify({ ok: false, error: "intervals must be a non-empty array" });
130
+ }
131
+ var timecodeRe = /^\d{2,3}:\d{2}:\d{2}$/;
132
+ for (var ii = 0; ii < args.intervals.length; ii++) {
133
+ var iv = args.intervals[ii];
134
+ if (!iv || typeof iv.start !== "string" || typeof iv.end !== "string" ||
135
+ !timecodeRe.test(iv.start) || !timecodeRe.test(iv.end)) {
136
+ return JSON.stringify({ ok: false, error: "each interval must have \"start\"/\"end\" as \"MM:SS:FF\" strings (index " + ii + ")" });
137
+ }
138
+ }
139
+
140
+ if (!app.project) {
141
+ return JSON.stringify({ ok: false, error: "no project open" });
142
+ }
143
+
144
+ var seq = null;
145
+ if (args.sequenceName && typeof args.sequenceName === "string") {
146
+ seq = findSequenceByName(args.sequenceName);
147
+ if (!seq) {
148
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
149
+ }
150
+ } else {
151
+ seq = app.project.activeSequence;
152
+ if (!seq) {
153
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
154
+ }
155
+ }
156
+
157
+ // QE DOM only ever operates on the active sequence tab — switch to it
158
+ // rather than erroring if the resolved sequence isn't already active.
159
+ if (app.project.activeSequence !== seq) {
160
+ app.project.activeSequence = seq;
161
+ }
162
+
163
+ try {
164
+ ensureQEEnabled();
165
+ } catch (e) {
166
+ return JSON.stringify({ ok: false, error: "app.enableQE() failed: " + e.toString() });
167
+ }
168
+ if (typeof qe === "undefined" || !qe.project) {
169
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
170
+ }
171
+ var qeSequence = qe.project.getActiveSequence();
172
+ if (!qeSequence) {
173
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() returned nothing after activating the sequence" });
174
+ }
175
+
176
+ if (args.audioTrackIndex >= qeSequence.numAudioTracks) {
177
+ return JSON.stringify({
178
+ ok: false,
179
+ error: "audioTrackIndex " + args.audioTrackIndex + " is out of range (sequence \"" + seq.name + "\" has " + qeSequence.numAudioTracks + " audio track(s))"
180
+ });
181
+ }
182
+ for (var vc = 0; vc < videoTrackIndices.length; vc++) {
183
+ if (videoTrackIndices[vc] >= qeSequence.numVideoTracks) {
184
+ return JSON.stringify({
185
+ ok: false,
186
+ error: "videoTrackIndices[" + vc + "]=" + videoTrackIndices[vc] + " is out of range (sequence \"" + seq.name + "\" has " + qeSequence.numVideoTracks + " video track(s))"
187
+ });
188
+ }
189
+ }
190
+
191
+ var fps = getSequenceFps(seq);
192
+
193
+ var parsedIntervals = [];
194
+ for (var pi = 0; pi < args.intervals.length; pi++) {
195
+ var rawInterval = args.intervals[pi];
196
+ var startSeconds = timecodeToSeconds(rawInterval.start, fps);
197
+ var endSeconds = timecodeToSeconds(rawInterval.end, fps);
198
+ if (endSeconds <= startSeconds) {
199
+ return JSON.stringify({ ok: false, error: "interval " + pi + " (\"" + rawInterval.start + "\" - \"" + rawInterval.end + "\") is empty or backwards" });
200
+ }
201
+ parsedIntervals.push({ start: rawInterval.start, end: rawInterval.end, startSeconds: startSeconds, endSeconds: endSeconds });
202
+ }
203
+ parsedIntervals.sort(function (a, b) { return a.startSeconds - b.startSeconds; });
204
+ for (var oi = 1; oi < parsedIntervals.length; oi++) {
205
+ if (parsedIntervals[oi].startSeconds < parsedIntervals[oi - 1].endSeconds) {
206
+ return JSON.stringify({
207
+ ok: false,
208
+ error: "intervals overlap (\"" + parsedIntervals[oi - 1].start + "\" - \"" + parsedIntervals[oi - 1].end +
209
+ "\" and \"" + parsedIntervals[oi].start + "\" - \"" + parsedIntervals[oi].end + "\")"
210
+ });
211
+ }
212
+ }
213
+
214
+ var tolerance = 0.5 / fps;
215
+ var warnings = [];
216
+ var totalSegmentsRemoved = 0;
217
+
218
+ // Process last-to-first: applying a cut ripples everything after it,
219
+ // so earlier (not-yet-processed) intervals' absolute positions stay
220
+ // valid until their own turn comes.
221
+ for (var idx = parsedIntervals.length - 1; idx >= 0; idx--) {
222
+ var interval = parsedIntervals[idx];
223
+
224
+ qeSequence.razor(toQeTimecode(interval.start));
225
+ qeSequence.razor(toQeTimecode(interval.end));
226
+
227
+ var audioTrack = qeSequence.getAudioTrackAt(args.audioTrackIndex);
228
+ totalSegmentsRemoved += findAndRemoveInRange(
229
+ audioTrack, interval.startSeconds, interval.endSeconds, tolerance, warnings, "Audio " + (args.audioTrackIndex + 1)
230
+ );
231
+
232
+ for (var vt = 0; vt < videoTrackIndices.length; vt++) {
233
+ var videoTrack = qeSequence.getVideoTrackAt(videoTrackIndices[vt]);
234
+ totalSegmentsRemoved += findAndRemoveInRange(
235
+ videoTrack, interval.startSeconds, interval.endSeconds, tolerance, warnings, "Video " + (videoTrackIndices[vt] + 1)
236
+ );
237
+ }
238
+ }
239
+
240
+ return JSON.stringify({
241
+ ok: true,
242
+ result: {
243
+ sequenceName: seq.name,
244
+ audioTrackIndex: args.audioTrackIndex,
245
+ videoTrackIndices: videoTrackIndices,
246
+ intervalsApplied: parsedIntervals.length,
247
+ totalSegmentsRemoved: totalSegmentsRemoved,
248
+ warnings: warnings
249
+ }
250
+ });
251
+ } catch (e) {
252
+ return JSON.stringify({ ok: false, error: e.toString() });
253
+ }
254
+ }