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.
- premiere_cli/__init__.py +11 -0
- premiere_cli/cli.py +3664 -0
- premiere_cli/log.py +66 -0
- premiere_cli/panel/.debug +8 -0
- premiere_cli/panel/CSXS/manifest.xml +52 -0
- premiere_cli/panel/css/style.css +53 -0
- premiere_cli/panel/host/commands/add-adjustment-layer.jsx +190 -0
- premiere_cli/panel/host/commands/add-audio-keyframes.jsx +176 -0
- premiere_cli/panel/host/commands/add-custom-metadata-field.jsx +63 -0
- premiere_cli/panel/host/commands/add-keyframe.jsx +181 -0
- premiere_cli/panel/host/commands/add-marker-to-project-item.jsx +194 -0
- premiere_cli/panel/host/commands/add-marker.jsx +129 -0
- premiere_cli/panel/host/commands/add-text-overlay.jsx +101 -0
- premiere_cli/panel/host/commands/add-to-render-queue.jsx +120 -0
- premiere_cli/panel/host/commands/add-to-timeline.jsx +300 -0
- premiere_cli/panel/host/commands/add-track.jsx +188 -0
- premiere_cli/panel/host/commands/add-transition.jsx +134 -0
- premiere_cli/panel/host/commands/adjust-audio-levels.jsx +132 -0
- premiere_cli/panel/host/commands/apply-audio-effect.jsx +118 -0
- premiere_cli/panel/host/commands/apply-effect.jsx +122 -0
- premiere_cli/panel/host/commands/apply-lut.jsx +107 -0
- premiere_cli/panel/host/commands/attach-custom-property.jsx +66 -0
- premiere_cli/panel/host/commands/auto-reframe-sequence.jsx +124 -0
- premiere_cli/panel/host/commands/batch-add-transitions.jsx +158 -0
- premiere_cli/panel/host/commands/batch-apply-effect.jsx +182 -0
- premiere_cli/panel/host/commands/batch-rename-clips.jsx +170 -0
- premiere_cli/panel/host/commands/batch-set-clips-enabled.jsx +145 -0
- premiere_cli/panel/host/commands/clear-item-in-out.jsx +117 -0
- premiere_cli/panel/host/commands/clear-sequence-in-out.jsx +100 -0
- premiere_cli/panel/host/commands/close-all-source-clips.jsx +32 -0
- premiere_cli/panel/host/commands/close-sequence.jsx +80 -0
- premiere_cli/panel/host/commands/close-source-monitor.jsx +32 -0
- premiere_cli/panel/host/commands/color-correct.jsx +164 -0
- premiere_cli/panel/host/commands/copy-effect-values.jsx +183 -0
- premiere_cli/panel/host/commands/copy-effects-between-clips.jsx +234 -0
- premiere_cli/panel/host/commands/create-bars-and-tone.jsx +152 -0
- premiere_cli/panel/host/commands/create-bin.jsx +76 -0
- premiere_cli/panel/host/commands/create-caption-track.jsx +159 -0
- premiere_cli/panel/host/commands/create-sequence-from-clips.jsx +170 -0
- premiere_cli/panel/host/commands/create-sequence-from-preset.jsx +90 -0
- premiere_cli/panel/host/commands/create-sequence.jsx +166 -0
- premiere_cli/panel/host/commands/create-smart-bin.jsx +80 -0
- premiere_cli/panel/host/commands/create-subclip.jsx +248 -0
- premiere_cli/panel/host/commands/create-subsequence.jsx +136 -0
- premiere_cli/panel/host/commands/debug-qe-inspect.jsx +248 -0
- premiere_cli/panel/host/commands/debug-qe-try-mutate.jsx +305 -0
- premiere_cli/panel/host/commands/delete-marker.jsx +178 -0
- premiere_cli/panel/host/commands/deselect-all-clips.jsx +98 -0
- premiere_cli/panel/host/commands/detach-proxy.jsx +116 -0
- premiere_cli/panel/host/commands/duplicate-clip.jsx +140 -0
- premiere_cli/panel/host/commands/duplicate-sequence.jsx +150 -0
- premiere_cli/panel/host/commands/encode-file.jsx +86 -0
- premiere_cli/panel/host/commands/encode-project-item.jsx +145 -0
- premiere_cli/panel/host/commands/export-aaf.jsx +77 -0
- premiere_cli/panel/host/commands/export-fcp-xml.jsx +65 -0
- premiere_cli/panel/host/commands/export-frame.jsx +381 -0
- premiere_cli/panel/host/commands/export-omf.jsx +95 -0
- premiere_cli/panel/host/commands/export-sequence-as-project.jsx +65 -0
- premiere_cli/panel/host/commands/export-sequence.jsx +100 -0
- premiere_cli/panel/host/commands/extract-audio-track.jsx +181 -0
- premiere_cli/panel/host/commands/extract-selection.jsx +113 -0
- premiere_cli/panel/host/commands/find-items-by-media-path.jsx +112 -0
- premiere_cli/panel/host/commands/freeze-frame.jsx +215 -0
- premiere_cli/panel/host/commands/get-active-sequence.jsx +103 -0
- premiere_cli/panel/host/commands/get-all-project-paths.jsx +72 -0
- premiere_cli/panel/host/commands/get-bin-contents.jsx +176 -0
- premiere_cli/panel/host/commands/get-clip-adjustment-layer.jsx +83 -0
- premiere_cli/panel/host/commands/get-clip-at-playhead.jsx +99 -0
- premiere_cli/panel/host/commands/get-clip-at-position.jsx +120 -0
- premiere_cli/panel/host/commands/get-clip-links.jsx +135 -0
- premiere_cli/panel/host/commands/get-clip-markers.jsx +144 -0
- premiere_cli/panel/host/commands/get-clip-speed.jsx +69 -0
- premiere_cli/panel/host/commands/get-color-label.jsx +89 -0
- premiere_cli/panel/host/commands/get-color-space.jsx +99 -0
- premiere_cli/panel/host/commands/get-duplicate-media.jsx +78 -0
- premiere_cli/panel/host/commands/get-effect-properties.jsx +129 -0
- premiere_cli/panel/host/commands/get-encoder-presets.jsx +131 -0
- premiere_cli/panel/host/commands/get-export-file-extension.jsx +56 -0
- premiere_cli/panel/host/commands/get-footage-interpretation.jsx +113 -0
- premiere_cli/panel/host/commands/get-full-clip-info.jsx +162 -0
- premiere_cli/panel/host/commands/get-full-project-overview.jsx +193 -0
- premiere_cli/panel/host/commands/get-full-sequence-info.jsx +184 -0
- premiere_cli/panel/host/commands/get-graphics-white-luminance.jsx +31 -0
- premiere_cli/panel/host/commands/get-insertion-bin.jsx +35 -0
- premiere_cli/panel/host/commands/get-item-metadata.jsx +94 -0
- premiere_cli/panel/host/commands/get-keyframes.jsx +158 -0
- premiere_cli/panel/host/commands/get-mogrt-component.jsx +111 -0
- premiere_cli/panel/host/commands/get-next-edit-point.jsx +131 -0
- premiere_cli/panel/host/commands/get-offline-media.jsx +67 -0
- premiere_cli/panel/host/commands/get-open-projects.jsx +50 -0
- premiere_cli/panel/host/commands/get-premiere-state.jsx +164 -0
- premiere_cli/panel/host/commands/get-project-info.jsx +63 -0
- premiere_cli/panel/host/commands/get-project-item-info.jsx +247 -0
- premiere_cli/panel/host/commands/get-project-panel-metadata.jsx +30 -0
- premiere_cli/panel/host/commands/get-qe-clip-info.jsx +198 -0
- premiere_cli/panel/host/commands/get-render-queue-status.jsx +35 -0
- premiere_cli/panel/host/commands/get-sequence-count.jsx +24 -0
- premiere_cli/panel/host/commands/get-sequence-in-out.jsx +76 -0
- premiere_cli/panel/host/commands/get-sequence-markers-by-type.jsx +89 -0
- premiere_cli/panel/host/commands/get-source-monitor-info.jsx +34 -0
- premiere_cli/panel/host/commands/get-source-monitor-position.jsx +30 -0
- premiere_cli/panel/host/commands/get-target-tracks.jsx +76 -0
- premiere_cli/panel/host/commands/get-timeline-gaps.jsx +124 -0
- premiere_cli/panel/host/commands/get-timeline-summary.jsx +154 -0
- premiere_cli/panel/host/commands/get-total-clip-count.jsx +67 -0
- premiere_cli/panel/host/commands/get-track-info.jsx +117 -0
- premiere_cli/panel/host/commands/get-unused-media.jsx +99 -0
- premiere_cli/panel/host/commands/get-used-media-report.jsx +125 -0
- premiere_cli/panel/host/commands/get-value-at-time.jsx +135 -0
- premiere_cli/panel/host/commands/get-version-info.jsx +33 -0
- premiere_cli/panel/host/commands/get-work-area.jsx +52 -0
- premiere_cli/panel/host/commands/get-workspaces.jsx +29 -0
- premiere_cli/panel/host/commands/get-xmp-metadata.jsx +107 -0
- premiere_cli/panel/host/commands/import-ae-comps.jsx +129 -0
- premiere_cli/panel/host/commands/import-fcp-xml.jsx +103 -0
- premiere_cli/panel/host/commands/import-folder.jsx +193 -0
- premiere_cli/panel/host/commands/import-image-sequence.jsx +171 -0
- premiere_cli/panel/host/commands/import-media.jsx +217 -0
- premiere_cli/panel/host/commands/import-mogrt-from-library.jsx +105 -0
- premiere_cli/panel/host/commands/import-mogrt.jsx +111 -0
- premiere_cli/panel/host/commands/import-sequences-from-project.jsx +80 -0
- premiere_cli/panel/host/commands/insert-from-source.jsx +162 -0
- premiere_cli/panel/host/commands/inspect-dom-object.jsx +162 -0
- premiere_cli/panel/host/commands/invert-selection.jsx +114 -0
- premiere_cli/panel/host/commands/is-work-area-enabled.jsx +88 -0
- premiere_cli/panel/host/commands/lift-selection.jsx +106 -0
- premiere_cli/panel/host/commands/link-selection.jsx +111 -0
- premiere_cli/panel/host/commands/list-available-audio-effects.jsx +33 -0
- premiere_cli/panel/host/commands/list-available-audio-transitions.jsx +35 -0
- premiere_cli/panel/host/commands/list-available-effects.jsx +33 -0
- premiere_cli/panel/host/commands/list-available-transitions.jsx +74 -0
- premiere_cli/panel/host/commands/list-markers.jsx +69 -0
- premiere_cli/panel/host/commands/list-project-items.jsx +105 -0
- premiere_cli/panel/host/commands/lock-track.jsx +114 -0
- premiere_cli/panel/host/commands/manage-proxies.jsx +176 -0
- premiere_cli/panel/host/commands/match-frame.jsx +141 -0
- premiere_cli/panel/host/commands/move-clip-to-track.jsx +220 -0
- premiere_cli/panel/host/commands/move-clip.jsx +97 -0
- premiere_cli/panel/host/commands/move-items-to-bin.jsx +194 -0
- premiere_cli/panel/host/commands/move-playhead-to-edit.jsx +174 -0
- premiere_cli/panel/host/commands/move-playhead.jsx +137 -0
- premiere_cli/panel/host/commands/nest-clips.jsx +179 -0
- premiere_cli/panel/host/commands/open-in-source.jsx +117 -0
- premiere_cli/panel/host/commands/open-project.jsx +61 -0
- premiere_cli/panel/host/commands/overwrite-clip-at.jsx +350 -0
- premiere_cli/panel/host/commands/overwrite-from-source.jsx +150 -0
- premiere_cli/panel/host/commands/play-source-monitor.jsx +36 -0
- premiere_cli/panel/host/commands/play-timeline.jsx +24 -0
- premiere_cli/panel/host/commands/razor-all-tracks.jsx +171 -0
- premiere_cli/panel/host/commands/redo.jsx +69 -0
- premiere_cli/panel/host/commands/refresh-media.jsx +101 -0
- premiere_cli/panel/host/commands/relink-media.jsx +132 -0
- premiere_cli/panel/host/commands/remove-all-effects.jsx +114 -0
- premiere_cli/panel/host/commands/remove-effect-by-name.jsx +143 -0
- premiere_cli/panel/host/commands/remove-effect.jsx +122 -0
- premiere_cli/panel/host/commands/remove-from-timeline.jsx +93 -0
- premiere_cli/panel/host/commands/remove-keyframe-range.jsx +173 -0
- premiere_cli/panel/host/commands/remove-keyframe.jsx +192 -0
- premiere_cli/panel/host/commands/remove-selected-clips.jsx +126 -0
- premiere_cli/panel/host/commands/remove-track-intervals.jsx +254 -0
- premiere_cli/panel/host/commands/remove-transition.jsx +164 -0
- premiere_cli/panel/host/commands/rename-bin.jsx +88 -0
- premiere_cli/panel/host/commands/rename-clip.jsx +127 -0
- premiere_cli/panel/host/commands/rename-project-item.jsx +111 -0
- premiere_cli/panel/host/commands/rename-track.jsx +84 -0
- premiere_cli/panel/host/commands/replace-clip-media.jsx +140 -0
- premiere_cli/panel/host/commands/replace-clip.jsx +188 -0
- premiere_cli/panel/host/commands/reverse-clip.jsx +187 -0
- premiere_cli/panel/host/commands/ripple-delete-clip.jsx +156 -0
- premiere_cli/panel/host/commands/roll-edit.jsx +162 -0
- premiere_cli/panel/host/commands/save-project-as.jsx +55 -0
- premiere_cli/panel/host/commands/save-project.jsx +57 -0
- premiere_cli/panel/host/commands/scene-edit-detection.jsx +128 -0
- premiere_cli/panel/host/commands/search-project-items.jsx +180 -0
- premiere_cli/panel/host/commands/select-all-clips.jsx +107 -0
- premiere_cli/panel/host/commands/select-clips-by-color.jsx +142 -0
- premiere_cli/panel/host/commands/select-clips-by-name.jsx +133 -0
- premiere_cli/panel/host/commands/select-clips-in-range.jsx +133 -0
- premiere_cli/panel/host/commands/select-disabled-clips.jsx +127 -0
- premiere_cli/panel/host/commands/select-project-item.jsx +115 -0
- premiere_cli/panel/host/commands/set-active-project.jsx +184 -0
- premiere_cli/panel/host/commands/set-active-sequence.jsx +87 -0
- premiere_cli/panel/host/commands/set-all-tracks-targeted.jsx +112 -0
- premiere_cli/panel/host/commands/set-anti-alias-quality.jsx +125 -0
- premiere_cli/panel/host/commands/set-blend-mode.jsx +111 -0
- premiere_cli/panel/host/commands/set-clip-anchor-point.jsx +102 -0
- premiere_cli/panel/host/commands/set-clip-enabled.jsx +127 -0
- premiere_cli/panel/host/commands/set-clip-opacity.jsx +102 -0
- premiere_cli/panel/host/commands/set-clip-pan.jsx +107 -0
- premiere_cli/panel/host/commands/set-clip-position.jsx +103 -0
- premiere_cli/panel/host/commands/set-clip-properties.jsx +221 -0
- premiere_cli/panel/host/commands/set-clip-rotation.jsx +102 -0
- premiere_cli/panel/host/commands/set-clip-scale.jsx +102 -0
- premiere_cli/panel/host/commands/set-clip-selection.jsx +144 -0
- premiere_cli/panel/host/commands/set-clip-speed.jsx +160 -0
- premiere_cli/panel/host/commands/set-clip-volume.jsx +128 -0
- premiere_cli/panel/host/commands/set-color-label.jsx +123 -0
- premiere_cli/panel/host/commands/set-color-value.jsx +155 -0
- premiere_cli/panel/host/commands/set-effect-property.jsx +124 -0
- premiere_cli/panel/host/commands/set-footage-interpretation.jsx +173 -0
- premiere_cli/panel/host/commands/set-frame-blend.jsx +145 -0
- premiere_cli/panel/host/commands/set-graphics-white-luminance.jsx +73 -0
- premiere_cli/panel/host/commands/set-item-in-out.jsx +180 -0
- premiere_cli/panel/host/commands/set-item-metadata.jsx +134 -0
- premiere_cli/panel/host/commands/set-item-offline.jsx +109 -0
- premiere_cli/panel/host/commands/set-item-start-time.jsx +139 -0
- premiere_cli/panel/host/commands/set-keyframe-interpolation.jsx +186 -0
- premiere_cli/panel/host/commands/set-override-frame-rate.jsx +123 -0
- premiere_cli/panel/host/commands/set-override-pixel-aspect-ratio.jsx +129 -0
- premiere_cli/panel/host/commands/set-poster-frame.jsx +192 -0
- premiere_cli/panel/host/commands/set-project-panel-metadata.jsx +69 -0
- premiere_cli/panel/host/commands/set-scale-to-frame-size.jsx +101 -0
- premiere_cli/panel/host/commands/set-scale-width-height.jsx +140 -0
- premiere_cli/panel/host/commands/set-sequence-in-out.jsx +65 -0
- premiere_cli/panel/host/commands/set-sequence-settings.jsx +184 -0
- premiere_cli/panel/host/commands/set-source-in-out.jsx +98 -0
- premiere_cli/panel/host/commands/set-target-track.jsx +91 -0
- premiere_cli/panel/host/commands/set-time-interpolation.jsx +141 -0
- premiere_cli/panel/host/commands/set-track-mute.jsx +91 -0
- premiere_cli/panel/host/commands/set-track-visibility.jsx +94 -0
- premiere_cli/panel/host/commands/set-transcode-on-ingest.jsx +78 -0
- premiere_cli/panel/host/commands/set-uniform-scale.jsx +104 -0
- premiere_cli/panel/host/commands/set-work-area.jsx +76 -0
- premiere_cli/panel/host/commands/set-workspace.jsx +35 -0
- premiere_cli/panel/host/commands/set-xmp-metadata.jsx +157 -0
- premiere_cli/panel/host/commands/slide-edit.jsx +162 -0
- premiere_cli/panel/host/commands/slip-edit.jsx +167 -0
- premiere_cli/panel/host/commands/split-clip.jsx +144 -0
- premiere_cli/panel/host/commands/stabilize-clip.jsx +139 -0
- premiere_cli/panel/host/commands/stop-playback.jsx +23 -0
- premiere_cli/panel/host/commands/trim-clip.jsx +111 -0
- premiere_cli/panel/host/commands/undo.jsx +114 -0
- premiere_cli/panel/host/commands/unlink-selection.jsx +106 -0
- premiere_cli/panel/host/commands/unnest-sequence.jsx +207 -0
- premiere_cli/panel/host/commands/update-marker.jsx +120 -0
- premiere_cli/panel/host/index.jsx +1227 -0
- premiere_cli/panel/host/presets/default-4k-25fps.sqpreset +63 -0
- premiere_cli/panel/index.html +16 -0
- premiere_cli/panel/js/cs-interface.js +11 -0
- premiere_cli/panel/js/main.js +409 -0
- premiere_cli/panel_install.py +220 -0
- premiere_cli-0.2.0.dist-info/METADATA +127 -0
- premiere_cli-0.2.0.dist-info/RECORD +247 -0
- premiere_cli-0.2.0.dist-info/WHEEL +5 -0
- premiere_cli-0.2.0.dist-info/entry_points.txt +3 -0
- premiere_cli-0.2.0.dist-info/licenses/LICENSE +428 -0
- 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
|
+
}
|