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,381 @@
1
+ // Command: export-frame → ppb_exportFrame
2
+ // Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
3
+ // same global ExtendScript context — shared helpers (ensureQEEnabled,
4
+ // findSequenceByName, findBundledPresetByRelativePath, trySetSequenceRange,
5
+ // getSequenceFps, timecodeToSeconds, ...) are already defined there.
6
+
7
+ // A bundled still-image preset for the ppb_exportFrame AME fallback (see
8
+ // below) — confirmed present on this machine's Premiere Pro 2026 install
9
+ // at this relative path; re-verify after a Premiere version upgrade, same
10
+ // caveat as extract-audio-track's FORMAT_PRESET_RELATIVE_PATHS. "Match
11
+ // Source" means the preset inherits the sequence's own frame size, so no
12
+ // width/height override is needed when using it.
13
+ var STILL_IMAGE_PRESET_RELATIVE_PATH =
14
+ "Contents/MediaIO/systempresets/3F3F3F3F_504E4720/PNG Sequence (Match Source).epr";
15
+
16
+ // The QE exportFramePNG call (see ppb_exportFrame) and the AME
17
+ // image-sequence export below can both write under a name other than the
18
+ // exact path requested — QE appends ".png" even to an already-.png-
19
+ // suffixed path ("frame.png" → "frame.png.png", confirmed live), and
20
+ // Premiere treats a still-image preset as a one-frame image *sequence*,
21
+ // appending a frame number to the base name ("frame.png" → "frame0.png",
22
+ // confirmed live; padding may vary by preset/duration). Finds whichever
23
+ // variant was actually written and renames it to the exact requested
24
+ // path so callers reliably get the file where they asked for it.
25
+ //
26
+ // Known variants are checked DIRECTLY by path, not found via a directory
27
+ // scan: enumerating the parent directory returns an empty list on this
28
+ // machine for some directories (e.g. /tmp — same macOS TCC/sandboxing
29
+ // behavior already documented for /Applications in
30
+ // findBundledPresetByRelativePath's notes in host/index.jsx) even though
31
+ // the files themselves are readable at their exact paths. A directory
32
+ // scan runs only as a last resort, for variant names not in the known
33
+ // list.
34
+ function locateAndNormalizeExportedFrame(outputPath) {
35
+ var exact = new File(outputPath);
36
+ if (exact.exists && exact.length > 0) {
37
+ return exact;
38
+ }
39
+
40
+ var fullName = decodeURI(exact.name);
41
+ var dot = fullName.lastIndexOf(".");
42
+ var base = dot === -1 ? fullName : fullName.substring(0, dot);
43
+ var ext = dot === -1 ? "" : fullName.substring(dot);
44
+ var parentPath = exact.path;
45
+
46
+ function normalize(produced) {
47
+ if (produced.length <= 0) {
48
+ return null;
49
+ }
50
+ try {
51
+ if (produced.fsName !== exact.fsName) {
52
+ produced.rename(fullName);
53
+ }
54
+ } catch (e) {
55
+ // rename best-effort — still report the file under whatever name it has
56
+ return produced;
57
+ }
58
+ return exact.exists ? exact : produced;
59
+ }
60
+
61
+ var knownVariants = [
62
+ outputPath + ".png", // QE double-extension quirk
63
+ parentPath + "/" + base + "0" + ext, // AME frame-number suffix
64
+ parentPath + "/" + base + "00" + ext,
65
+ parentPath + "/" + base + "000" + ext,
66
+ parentPath + "/" + base + "0000" + ext
67
+ ];
68
+ for (var v = 0; v < knownVariants.length; v++) {
69
+ var candidate = new File(knownVariants[v]);
70
+ if (candidate.exists && candidate.length > 0) {
71
+ return normalize(candidate);
72
+ }
73
+ }
74
+
75
+ // Last resort: scan the parent directory (returns nothing at all in
76
+ // enumeration-blocked directories — see comment above).
77
+ var dir = exact.parent;
78
+ if (!dir || !dir.exists) {
79
+ return null;
80
+ }
81
+
82
+ var matches = dir.getFiles(function (item) {
83
+ if (item instanceof Folder) {
84
+ return false;
85
+ }
86
+ var name = decodeURI(item.name);
87
+ if (name.indexOf(base) !== 0) {
88
+ return false;
89
+ }
90
+ var lowerExt = ext.toLowerCase();
91
+ return lowerExt === "" || name.toLowerCase().substring(name.length - lowerExt.length) === lowerExt;
92
+ });
93
+
94
+ if (!matches || matches.length === 0) {
95
+ return null;
96
+ }
97
+
98
+ return normalize(matches[0]);
99
+ }
100
+
101
+ // Exports a single frame of a sequence, at a given timecode, to a PNG file.
102
+ // qeSeq.exportFramePNG's argument order is version-dependent (per
103
+ // PREMIERE_API_NOTES.md) and can silently write nothing on some builds —
104
+ // this brute-forces a short list of plausible signatures and judges success
105
+ // only by checking the filesystem for a real output file afterward, never
106
+ // by trusting the call's own return value (same pattern as
107
+ // remove-track-intervals' rippleDelete()/remove() guessing).
108
+ function ppb_exportFrame(argsJson) {
109
+ try {
110
+ var args;
111
+ try {
112
+ args = JSON.parse(argsJson);
113
+ } catch (e) {
114
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
115
+ }
116
+
117
+ if (!args.outputPath || typeof args.outputPath !== "string") {
118
+ return JSON.stringify({ ok: false, error: "outputPath is required" });
119
+ }
120
+ var timecodeRe = /^\d{2,3}:\d{2}:\d{2}$/;
121
+ if (!args.timecode || typeof args.timecode !== "string" || !timecodeRe.test(args.timecode)) {
122
+ return JSON.stringify({ ok: false, error: "timecode must be a \"MM:SS:FF\" string" });
123
+ }
124
+
125
+ if (!app.project) {
126
+ return JSON.stringify({ ok: false, error: "no project open" });
127
+ }
128
+
129
+ var seq = null;
130
+ if (args.sequenceName && typeof args.sequenceName === "string") {
131
+ seq = findSequenceByName(args.sequenceName);
132
+ if (!seq) {
133
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
134
+ }
135
+ } else {
136
+ seq = app.project.activeSequence;
137
+ if (!seq) {
138
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
139
+ }
140
+ }
141
+
142
+ // QE DOM only ever operates on the active sequence tab — switch to it
143
+ // rather than erroring if the resolved sequence isn't already active
144
+ // (same approach as ppb_removeTrackIntervals).
145
+ if (app.project.activeSequence !== seq) {
146
+ app.project.activeSequence = seq;
147
+ }
148
+
149
+ try {
150
+ ensureQEEnabled();
151
+ } catch (e) {
152
+ return JSON.stringify({ ok: false, error: "app.enableQE() failed: " + e.toString() });
153
+ }
154
+ if (typeof qe === "undefined" || !qe.project) {
155
+ return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
156
+ }
157
+ var qeSequence = qe.project.getActiveSequence();
158
+ if (!qeSequence) {
159
+ return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() returned nothing after activating the sequence" });
160
+ }
161
+
162
+ var fps = getSequenceFps(seq);
163
+ var timeSeconds = timecodeToSeconds(args.timecode, fps);
164
+
165
+ var width = null;
166
+ var height = null;
167
+ try {
168
+ var settings = seq.getSettings();
169
+ width = settings.videoFrameWidth;
170
+ height = settings.videoFrameHeight;
171
+ } catch (e) {
172
+ // best-effort only — width/height-based attempts below are simply skipped if unreadable
173
+ }
174
+
175
+ // --- Snapshot playhead position, to restore afterward regardless of outcome ---
176
+ var originalPosition = null;
177
+ try {
178
+ originalPosition = seq.getPlayerPosition();
179
+ } catch (e) {
180
+ originalPosition = null;
181
+ }
182
+
183
+ var positionAttempts = [];
184
+ var ticksString = String(Math.round(timeSeconds * TICKS_PER_SECOND));
185
+ var timeObj = null;
186
+ try {
187
+ timeObj = new Time();
188
+ timeObj.seconds = timeSeconds;
189
+ } catch (e) {
190
+ timeObj = null;
191
+ }
192
+
193
+ var positionSet = false;
194
+ try {
195
+ seq.setPlayerPosition(ticksString);
196
+ positionAttempts.push({ form: "ticksString", success: true });
197
+ positionSet = true;
198
+ } catch (e) {
199
+ positionAttempts.push({ form: "ticksString", success: false, error: e.toString() });
200
+ }
201
+ if (!positionSet && timeObj !== null) {
202
+ try {
203
+ seq.setPlayerPosition(timeObj);
204
+ positionAttempts.push({ form: "TimeObject", success: true });
205
+ positionSet = true;
206
+ } catch (e) {
207
+ positionAttempts.push({ form: "TimeObject", success: false, error: e.toString() });
208
+ }
209
+ }
210
+
211
+ var result = {
212
+ sequenceName: seq.name,
213
+ timecode: args.timecode,
214
+ timeSeconds: timeSeconds,
215
+ outputPath: args.outputPath,
216
+ width: width,
217
+ height: height
218
+ };
219
+
220
+ try {
221
+ if (!positionSet) {
222
+ return JSON.stringify({
223
+ ok: false,
224
+ error: "could not move the playhead to the requested timecode with any known argument form (ticks string, Time object)",
225
+ attempts: positionAttempts
226
+ });
227
+ }
228
+
229
+ // Clear any stale leftovers from an earlier failed run — the exact
230
+ // requested path plus every known name variant Premiere might have
231
+ // written it under (see locateAndNormalizeExportedFrame) — so a
232
+ // leftover file's mere existence can't be mistaken for this run's
233
+ // output. Loops because multiple variants can coexist (e.g. one QE
234
+ // double-extension file AND one AME frame-numbered file).
235
+ for (var staleRound = 0; staleRound < 8; staleRound++) {
236
+ var stale = locateAndNormalizeExportedFrame(args.outputPath);
237
+ if (stale === null) {
238
+ break;
239
+ }
240
+ try {
241
+ stale.remove();
242
+ } catch (e) {
243
+ // best-effort — a failed cleanup doesn't block the export attempt
244
+ break;
245
+ }
246
+ }
247
+
248
+ // --- Path 1: QE DOM's exportFramePNG. Version-inconsistent arg
249
+ // order (per PREMIERE_API_NOTES.md) and confirmed live to sometimes
250
+ // return false / write nothing regardless of a syntactically
251
+ // correct call — verify by scanning the filesystem afterward, never
252
+ // by trusting the call's return value.
253
+ var guesses = [];
254
+ guesses.push({ args: [args.outputPath], call: [args.outputPath] });
255
+ if (width !== null && height !== null) {
256
+ guesses.push({ args: [args.outputPath, String(width), String(height)], call: [args.outputPath, String(width), String(height)] });
257
+ }
258
+ // Confirmed live on this Premiere build: passing the output path as
259
+ // BOTH arguments succeeds where sensible width/height strings do
260
+ // not — an undocumented quirk of this exportFramePNG build, kept as
261
+ // a guess rather than relied on, since other builds may differ.
262
+ guesses.push({ args: [args.outputPath, args.outputPath], call: [args.outputPath, args.outputPath] });
263
+ if (timeObj !== null) {
264
+ guesses.push({ args: ["<Time seconds=" + timeSeconds + ">", args.outputPath], call: [timeObj, args.outputPath] });
265
+ }
266
+ guesses.push({ args: [ticksString, args.outputPath], call: [ticksString, args.outputPath] });
267
+
268
+ var attempts = [];
269
+ var succeededWithArgs = null;
270
+ var qeProducedFile = null;
271
+
272
+ for (var g = 0; g < guesses.length && succeededWithArgs === null; g++) {
273
+ var guess = guesses[g];
274
+ try {
275
+ qeSequence.exportFramePNG.apply(qeSequence, guess.call);
276
+ } catch (e) {
277
+ attempts.push({ args: guess.args, success: false, error: e.toString() });
278
+ continue;
279
+ }
280
+
281
+ var producedFile = locateAndNormalizeExportedFrame(args.outputPath);
282
+ if (producedFile !== null) {
283
+ attempts.push({ args: guess.args, success: true });
284
+ succeededWithArgs = guess.args;
285
+ qeProducedFile = producedFile;
286
+ } else {
287
+ attempts.push({ args: guess.args, success: false, error: "no file produced" });
288
+ }
289
+ }
290
+
291
+ if (succeededWithArgs !== null) {
292
+ result.method = "qe";
293
+ result.attempts = attempts;
294
+ result.succeededWithArgs = succeededWithArgs;
295
+ result.fileSizeBytes = qeProducedFile.length;
296
+ return JSON.stringify({ ok: true, result: result });
297
+ }
298
+
299
+ // --- Path 2: every QE guess failed — fall back to a one-frame
300
+ // export through Adobe Media Encoder via the standard DOM's
301
+ // exportAsMediaDirect(), the same documented, blocking mechanism
302
+ // ppb_extractAudioTrack already uses successfully. Narrows the
303
+ // sequence's in/out points to exactly one frame (using the
304
+ // sequence's own frame duration, seq.timebase) around the target
305
+ // timecode, then restores the original in/out points afterward.
306
+ var amePresetPath = findBundledPresetByRelativePath(STILL_IMAGE_PRESET_RELATIVE_PATH);
307
+ if (!amePresetPath) {
308
+ return JSON.stringify({
309
+ ok: false,
310
+ error: "exportFramePNG failed with all known arg-order variants, and no bundled still-image preset was found for the Media Encoder fallback",
311
+ attempts: attempts
312
+ });
313
+ }
314
+
315
+ var originalInPoint = null;
316
+ var originalOutPoint = null;
317
+ try {
318
+ originalInPoint = seq.getInPoint();
319
+ originalOutPoint = seq.getOutPoint();
320
+ } catch (e) {
321
+ // best-effort only — if these can't be read, we simply won't restore them
322
+ }
323
+
324
+ var frameDurationSeconds = 1 / fps;
325
+ var ameProducedFile = null;
326
+ var ameError = null;
327
+
328
+ try {
329
+ var rangeOutcome = trySetSequenceRange(seq, timeSeconds, timeSeconds + frameDurationSeconds);
330
+ if (!rangeOutcome.ok) {
331
+ ameError = "could not set sequence in/out points with any known argument form (seconds, ticks string, Time object)";
332
+ } else {
333
+ try {
334
+ seq.exportAsMediaDirect(args.outputPath, amePresetPath, 1 /* ENCODE_IN_TO_OUT */);
335
+ } catch (e) {
336
+ ameError = "exportAsMediaDirect failed: " + e.toString();
337
+ }
338
+ }
339
+ } finally {
340
+ if (originalInPoint !== null && originalOutPoint !== null) {
341
+ try {
342
+ trySetSequenceRange(seq, originalInPoint.seconds, originalOutPoint.seconds);
343
+ } catch (e) {
344
+ // best-effort
345
+ }
346
+ }
347
+ }
348
+
349
+ if (ameError === null) {
350
+ ameProducedFile = locateAndNormalizeExportedFrame(args.outputPath);
351
+ }
352
+
353
+ if (ameProducedFile === null) {
354
+ return JSON.stringify({
355
+ ok: false,
356
+ error: "exportFramePNG failed with all known arg-order variants, and the Media Encoder fallback also failed" +
357
+ (ameError ? ": " + ameError : " (no file produced)"),
358
+ attempts: attempts
359
+ });
360
+ }
361
+
362
+ result.method = "ame";
363
+ result.attempts = attempts;
364
+ result.presetPath = amePresetPath;
365
+ result.fileSizeBytes = ameProducedFile.length;
366
+
367
+ return JSON.stringify({ ok: true, result: result });
368
+ } finally {
369
+ // Always restore the original playhead position, even if export threw.
370
+ if (originalPosition !== null) {
371
+ try {
372
+ seq.setPlayerPosition(originalPosition.ticks);
373
+ } catch (e) {
374
+ // best-effort — restoration failure doesn't change the command's outcome
375
+ }
376
+ }
377
+ }
378
+ } catch (e) {
379
+ return JSON.stringify({ ok: false, error: e.toString() });
380
+ }
381
+ }
@@ -0,0 +1,95 @@
1
+ // Command: export-omf → ppb_exportOmf
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
+ // Exports the given (or active) sequence as an OMF file via
7
+ // app.project.exportOMF(seq, path, title, rate, bits, encapsulated01,
8
+ // audioFileFormat, trim01, handleFrames) (PREMIERE_API_NOTES.md's "FCP XML
9
+ // / AAF / OMF / EDL" line). Argument order/defaults mirror the reference
10
+ // tool this ports (leancoderkavy's premiere-pro-mcp export_omf) — this
11
+ // specific 9-arg signature is UNCONFIRMED against our own Premiere build
12
+ // (never live-tested), so a thrown "wrong number/type of arguments" error
13
+ // here would indicate the real signature differs.
14
+
15
+ function ppb_exportOmf(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.outputPath || typeof args.outputPath !== "string") {
25
+ return JSON.stringify({ ok: false, error: "outputPath is required" });
26
+ }
27
+
28
+ if (!app.project) {
29
+ return JSON.stringify({ ok: false, error: "no project open" });
30
+ }
31
+
32
+ var seq = null;
33
+ if (args.sequenceName && typeof args.sequenceName === "string") {
34
+ seq = findSequenceByName(args.sequenceName);
35
+ if (!seq) {
36
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
37
+ }
38
+ } else {
39
+ seq = app.project.activeSequence;
40
+ if (!seq) {
41
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
42
+ }
43
+ }
44
+
45
+ var title = typeof args.title === "string" ? args.title : "OMFTitle";
46
+ var rate = typeof args.rate === "number" ? args.rate : 48000;
47
+ var bits = typeof args.bits === "number" ? args.bits : 16;
48
+ var audioEncapsulated = args.audioEncapsulated !== false; // default true
49
+ var audioFileFormat = typeof args.audioFileFormat === "number" ? args.audioFileFormat : 1; // 0=AIFF, 1=WAV
50
+ var trimAudioFiles = args.trimAudioFiles !== false; // default true
51
+ var handleFrames = typeof args.handleFrames === "number" ? args.handleFrames : 1000;
52
+
53
+ var result = {
54
+ sequenceName: seq.name,
55
+ outputPath: args.outputPath,
56
+ title: title,
57
+ rate: rate,
58
+ bits: bits,
59
+ audioEncapsulated: audioEncapsulated,
60
+ audioFileFormat: audioFileFormat,
61
+ trimAudioFiles: trimAudioFiles,
62
+ handleFrames: handleFrames
63
+ };
64
+
65
+ try {
66
+ app.project.exportOMF(
67
+ seq,
68
+ args.outputPath,
69
+ title,
70
+ rate,
71
+ bits,
72
+ audioEncapsulated ? 1 : 0,
73
+ audioFileFormat,
74
+ trimAudioFiles ? 1 : 0,
75
+ handleFrames
76
+ );
77
+ } catch (e) {
78
+ return JSON.stringify({ ok: false, error: "exportOMF failed: " + e.toString() });
79
+ }
80
+
81
+ var outFile = new File(args.outputPath);
82
+ if (!outFile.exists) {
83
+ return JSON.stringify({
84
+ ok: false,
85
+ error: "exportOMF ran but no file was written to " + args.outputPath
86
+ });
87
+ }
88
+
89
+ result.fileSizeBytes = outFile.length;
90
+
91
+ return JSON.stringify({ ok: true, result: result });
92
+ } catch (e) {
93
+ return JSON.stringify({ ok: false, error: e.toString() });
94
+ }
95
+ }
@@ -0,0 +1,65 @@
1
+ // Command: export-sequence-as-project → ppb_exportSequenceAsProject
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
+ // Ported from leancoderkavy/premiere-pro-mcp's advanced.ts
7
+ // export_as_project tool: `seq.exportAsProject(outputPath)` per
8
+ // PREMIERE_API_NOTES.md's Sequences table. Verified via the filesystem —
9
+ // never the call's own (undocumented) return value — same rule as
10
+ // export-frame.jsx and every other file-producing command in this panel.
11
+ function ppb_exportSequenceAsProject(argsJson) {
12
+ try {
13
+ var args;
14
+ try {
15
+ args = JSON.parse(argsJson);
16
+ } catch (e) {
17
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
18
+ }
19
+
20
+ if (!app.project) {
21
+ return JSON.stringify({ ok: false, error: "no project open" });
22
+ }
23
+ if (!args.outputPath || typeof args.outputPath !== "string") {
24
+ return JSON.stringify({ ok: false, error: "outputPath is required" });
25
+ }
26
+
27
+ var seq;
28
+ if (args.sequenceName && typeof args.sequenceName === "string") {
29
+ seq = findSequenceByName(args.sequenceName);
30
+ if (!seq) {
31
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
32
+ }
33
+ } else {
34
+ seq = app.project.activeSequence;
35
+ if (!seq) {
36
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
37
+ }
38
+ }
39
+
40
+ try {
41
+ seq.exportAsProject(args.outputPath);
42
+ } catch (e) {
43
+ return JSON.stringify({ ok: false, error: "seq.exportAsProject() failed: " + e.toString() });
44
+ }
45
+
46
+ var outFile = new File(args.outputPath);
47
+ if (!outFile.exists) {
48
+ return JSON.stringify({ ok: false, error: "exportAsProject() did not throw, but no file was found at " + args.outputPath });
49
+ }
50
+
51
+ var fileSizeBytes = null;
52
+ try { fileSizeBytes = outFile.length; } catch (e) { fileSizeBytes = null; }
53
+
54
+ return JSON.stringify({
55
+ ok: true,
56
+ result: {
57
+ sequenceName: seq.name,
58
+ outputPath: args.outputPath,
59
+ fileSizeBytes: fileSizeBytes
60
+ }
61
+ });
62
+ } catch (e) {
63
+ return JSON.stringify({ ok: false, error: e.toString() });
64
+ }
65
+ }
@@ -0,0 +1,100 @@
1
+ // Command: export-sequence → ppb_exportSequence
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
+ // Exports the given (or active) sequence to a local file via the standard
7
+ // DOM's blocking seq.exportAsMediaDirect() — same synchronous, no-AME-
8
+ // dependency mechanism ppb_extractAudioTrack/ppb_exportFrame already use
9
+ // successfully (PREMIERE_API_NOTES.md: "Export direct (blocking)").
10
+ // Requires an explicit .epr presetPath — no default/auto-discovered preset
11
+ // (unlike extract-audio-track's bundled-audio-preset convenience), since
12
+ // video export presets vary too widely to guess a sane default.
13
+
14
+ // range → workAreaType per PREMIERE_API_NOTES.md's exportAsMediaDirect line:
15
+ // 0 = ENCODE_ENTIRE, 1 = ENCODE_IN_TO_OUT, 2 = ENCODE_WORKAREA.
16
+ function ppbExportSequenceRangeToWorkAreaType(range) {
17
+ if (range === "entire" || range === undefined || range === null) {
18
+ return { value: 0, label: "entire" };
19
+ }
20
+ if (range === "in-to-out") {
21
+ return { value: 1, label: "in-to-out" };
22
+ }
23
+ if (range === "work-area") {
24
+ return { value: 2, label: "work-area" };
25
+ }
26
+ return null;
27
+ }
28
+
29
+ function ppb_exportSequence(argsJson) {
30
+ try {
31
+ var args;
32
+ try {
33
+ args = JSON.parse(argsJson);
34
+ } catch (e) {
35
+ return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
36
+ }
37
+
38
+ if (!args.outputPath || typeof args.outputPath !== "string") {
39
+ return JSON.stringify({ ok: false, error: "outputPath is required" });
40
+ }
41
+ if (!args.presetPath || typeof args.presetPath !== "string") {
42
+ return JSON.stringify({ ok: false, error: "presetPath is required (an absolute .epr file path)" });
43
+ }
44
+
45
+ if (!app.project) {
46
+ return JSON.stringify({ ok: false, error: "no project open" });
47
+ }
48
+
49
+ var seq = null;
50
+ if (args.sequenceName && typeof args.sequenceName === "string") {
51
+ seq = findSequenceByName(args.sequenceName);
52
+ if (!seq) {
53
+ return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
54
+ }
55
+ } else {
56
+ seq = app.project.activeSequence;
57
+ if (!seq) {
58
+ return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
59
+ }
60
+ }
61
+
62
+ var rangeInfo = ppbExportSequenceRangeToWorkAreaType(args.range);
63
+ if (!rangeInfo) {
64
+ return JSON.stringify({ ok: false, error: "range must be one of \"entire\", \"in-to-out\", \"work-area\"" });
65
+ }
66
+
67
+ var presetFile = new File(args.presetPath);
68
+ if (!presetFile.exists) {
69
+ return JSON.stringify({ ok: false, error: "preset file not found: " + args.presetPath });
70
+ }
71
+
72
+ var result = {
73
+ sequenceName: seq.name,
74
+ outputPath: args.outputPath,
75
+ presetPath: args.presetPath,
76
+ range: rangeInfo.label
77
+ };
78
+
79
+ try {
80
+ seq.exportAsMediaDirect(args.outputPath, args.presetPath, rangeInfo.value);
81
+ } catch (e) {
82
+ return JSON.stringify({ ok: false, error: "exportAsMediaDirect failed: " + e.toString() });
83
+ }
84
+
85
+ var outFile = new File(args.outputPath);
86
+ if (!outFile.exists) {
87
+ return JSON.stringify({
88
+ ok: false,
89
+ error: "exportAsMediaDirect ran but no file was written to " + args.outputPath +
90
+ " (workAreaType=" + rangeInfo.value + ", preset=" + args.presetPath + ")"
91
+ });
92
+ }
93
+
94
+ result.fileSizeBytes = outFile.length;
95
+
96
+ return JSON.stringify({ ok: true, result: result });
97
+ } catch (e) {
98
+ return JSON.stringify({ ok: false, error: e.toString() });
99
+ }
100
+ }