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,1227 @@
|
|
|
1
|
+
// Premiere Bridge — ExtendScript loader and lazy command dispatcher.
|
|
2
|
+
//
|
|
3
|
+
// This file is the manifest's single <ScriptPath>, evaluated eagerly when
|
|
4
|
+
// the panel loads. It defines only the helpers shared by more than one
|
|
5
|
+
// command, plus ppb_dispatch() — each command's actual implementation
|
|
6
|
+
// lives in host/commands/<command-name>.jsx and is $.evalFile'd into this
|
|
7
|
+
// same global context the first time that command is called.
|
|
8
|
+
//
|
|
9
|
+
// Every ppb_-prefixed command function wraps its body in try/catch and
|
|
10
|
+
// always returns a JSON string itself — an uncaught exception here makes
|
|
11
|
+
// evalScript's callback receive only the unhelpful literal string
|
|
12
|
+
// "EvalScript error." with no detail. ppb_dispatch follows the same rule
|
|
13
|
+
// for load/dispatch failures.
|
|
14
|
+
|
|
15
|
+
var TICKS_PER_SECOND = 254016000000;
|
|
16
|
+
|
|
17
|
+
// The QE (Quality Engineering) DOM — app.enableQE(); qe.project... — is
|
|
18
|
+
// undocumented but required for several operations the standard DOM can't
|
|
19
|
+
// do without a dialog (sequence creation from a preset, razor, frame
|
|
20
|
+
// export). See host/QE_DOM_NOTES.md and host/PREMIERE_API_NOTES.md.
|
|
21
|
+
function ensureQEEnabled() {
|
|
22
|
+
if (typeof qe === "undefined") {
|
|
23
|
+
app.enableQE();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function findSequenceByName(name) {
|
|
28
|
+
for (var i = 0; i < app.project.sequences.numSequences; i++) {
|
|
29
|
+
if (app.project.sequences[i].name === name) {
|
|
30
|
+
return app.project.sequences[i];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// A handful of export presets ship inside the Premiere Pro app bundle
|
|
37
|
+
// itself — no need to bundle our own. Paths are relative to the app
|
|
38
|
+
// bundle root and resolved via app.path (the running app's own install
|
|
39
|
+
// location, always readable) rather than scanning /Applications: a
|
|
40
|
+
// directory listing of /Applications from inside the CEP panel returned
|
|
41
|
+
// nothing on this machine — likely macOS TCC/sandboxing blocking that
|
|
42
|
+
// enumeration even though the specific preset files themselves ARE
|
|
43
|
+
// readable.
|
|
44
|
+
function findBundledPresetByRelativePath(relativePath) {
|
|
45
|
+
try {
|
|
46
|
+
var appPath = app.path;
|
|
47
|
+
var bundleEnd = appPath.indexOf(".app");
|
|
48
|
+
if (bundleEnd === -1) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
var bundlePath = appPath.substring(0, bundleEnd + 4); // include ".app"
|
|
52
|
+
var presetFile = new File(bundlePath + "/" + relativePath);
|
|
53
|
+
if (presetFile.exists) {
|
|
54
|
+
return presetFile.fsName;
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
// fall through — caller reports "no preset found"
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// seq.setInPoint()/setOutPoint() argument type is inconsistent across
|
|
63
|
+
// Premiere versions in the wild (plain seconds vs. ticks string vs. Time
|
|
64
|
+
// object) — try each form in turn rather than guessing one and failing.
|
|
65
|
+
function trySetSequenceRange(seq, startSeconds, endSeconds) {
|
|
66
|
+
var attempts = [];
|
|
67
|
+
|
|
68
|
+
function attempt(label, inVal, outVal) {
|
|
69
|
+
try {
|
|
70
|
+
seq.setInPoint(inVal);
|
|
71
|
+
seq.setOutPoint(outVal);
|
|
72
|
+
attempts.push({ form: label, success: true });
|
|
73
|
+
return true;
|
|
74
|
+
} catch (e) {
|
|
75
|
+
attempts.push({ form: label, success: false, error: e.toString() });
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (attempt("seconds", startSeconds, endSeconds)) {
|
|
81
|
+
return { ok: true, attempts: attempts };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var startTicks = String(Math.round(startSeconds * TICKS_PER_SECOND));
|
|
85
|
+
var endTicks = String(Math.round(endSeconds * TICKS_PER_SECOND));
|
|
86
|
+
if (attempt("ticksString", startTicks, endTicks)) {
|
|
87
|
+
return { ok: true, attempts: attempts };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var startTime = new Time();
|
|
91
|
+
startTime.seconds = startSeconds;
|
|
92
|
+
var endTime = new Time();
|
|
93
|
+
endTime.seconds = endSeconds;
|
|
94
|
+
if (attempt("TimeObject", startTime, endTime)) {
|
|
95
|
+
return { ok: true, attempts: attempts };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { ok: false, attempts: attempts };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getSequenceFps(sequence) {
|
|
102
|
+
var frameDuration = sequence.getSettings().videoFrameRate;
|
|
103
|
+
var ticksPerFrame = parseInt(frameDuration.ticks, 10);
|
|
104
|
+
return Math.round(TICKS_PER_SECOND / ticksPerFrame);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function timecodeToSeconds(timecode, fps) {
|
|
108
|
+
var parts = timecode.split(":");
|
|
109
|
+
var minutes = parseInt(parts[0], 10);
|
|
110
|
+
var seconds = parseInt(parts[1], 10);
|
|
111
|
+
var frames = parseInt(parts[2], 10);
|
|
112
|
+
return minutes * 60 + seconds + frames / fps;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Shared clip serializer — used by get-active-sequence, get-full-sequence-
|
|
116
|
+
// info, get-full-clip-info, and get-timeline-summary (all standard-DOM
|
|
117
|
+
// reads, no QE needed). Every field is individually try/caught so one
|
|
118
|
+
// unreadable field never blanks out the rest of the clip. Seconds are read
|
|
119
|
+
// via a Time-like object's `.seconds` first (usually present), falling
|
|
120
|
+
// back to `.ticks` per PREMIERE_API_NOTES.md's ticks-are-strings rule.
|
|
121
|
+
function timeValueToSeconds(timeLike) {
|
|
122
|
+
if (timeLike === null || typeof timeLike === "undefined") {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
if (typeof timeLike.seconds === "number") {
|
|
126
|
+
return timeLike.seconds;
|
|
127
|
+
}
|
|
128
|
+
return Number(timeLike.ticks) / TICKS_PER_SECOND;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function serializeTrackItem(clip, trackIndex, clipIndex) {
|
|
132
|
+
var out = {
|
|
133
|
+
name: null,
|
|
134
|
+
trackIndex: trackIndex,
|
|
135
|
+
clipIndex: clipIndex,
|
|
136
|
+
nodeId: null,
|
|
137
|
+
startSeconds: null,
|
|
138
|
+
endSeconds: null,
|
|
139
|
+
inPointSeconds: null,
|
|
140
|
+
outPointSeconds: null,
|
|
141
|
+
durationSeconds: null,
|
|
142
|
+
mediaPath: null,
|
|
143
|
+
disabled: null
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
try { out.name = clip.name; } catch (e) { out.name = null; }
|
|
147
|
+
try { out.nodeId = clip.nodeId; } catch (e) { out.nodeId = null; }
|
|
148
|
+
try { out.startSeconds = timeValueToSeconds(clip.start); } catch (e) { out.startSeconds = null; }
|
|
149
|
+
try { out.endSeconds = timeValueToSeconds(clip.end); } catch (e) { out.endSeconds = null; }
|
|
150
|
+
try { out.inPointSeconds = timeValueToSeconds(clip.inPoint); } catch (e) { out.inPointSeconds = null; }
|
|
151
|
+
try { out.outPointSeconds = timeValueToSeconds(clip.outPoint); } catch (e) { out.outPointSeconds = null; }
|
|
152
|
+
try { out.durationSeconds = timeValueToSeconds(clip.duration); } catch (e) { out.durationSeconds = null; }
|
|
153
|
+
try { out.mediaPath = clip.projectItem.getMediaPath(); } catch (e) { out.mediaPath = null; }
|
|
154
|
+
try { out.disabled = clip.disabled; } catch (e) { out.disabled = null; }
|
|
155
|
+
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// Clip component/property helpers — shared by the wave-3 clip transform and
|
|
161
|
+
// opacity setter commands: set-clip-position, set-clip-scale,
|
|
162
|
+
// set-clip-rotation, set-clip-anchor-point, set-clip-opacity,
|
|
163
|
+
// set-uniform-scale, set-scale-width-height, set-anti-alias-quality, and
|
|
164
|
+
// set-blend-mode. Per PREMIERE_API_NOTES.md's "Effects, transitions,
|
|
165
|
+
// keyframes" section: components[0]=Motion/[1]=Opacity is only a
|
|
166
|
+
// convention, never a guarantee — identify a component by matchName
|
|
167
|
+
// ("AE.ADBE Motion"/"AE.ADBE Opacity") where possible, falling back to
|
|
168
|
+
// displayName. displayName matching is locale-dependent ("Nivel", "Pegel",
|
|
169
|
+
// "音量") — try an exact match first, then a normalized-lowercase match.
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
function normalizeDisplayName(name) {
|
|
173
|
+
return String(name).toLowerCase();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Finds a clip component (Motion/Opacity/an applied effect) by matchName
|
|
177
|
+
// first (exact, reliable, locale-independent), falling back to displayName
|
|
178
|
+
// (exact, then normalized-lowercase). matchNames/displayNames are arrays;
|
|
179
|
+
// either may be omitted/empty.
|
|
180
|
+
function findClipComponent(clip, matchNames, displayNames) {
|
|
181
|
+
var numComponents;
|
|
182
|
+
try {
|
|
183
|
+
numComponents = clip.components.numItems;
|
|
184
|
+
} catch (e) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (matchNames && matchNames.length) {
|
|
189
|
+
for (var i = 0; i < numComponents; i++) {
|
|
190
|
+
var comp = clip.components[i];
|
|
191
|
+
var mn = null;
|
|
192
|
+
try { mn = comp.matchName; } catch (e) { mn = null; }
|
|
193
|
+
if (mn) {
|
|
194
|
+
for (var m = 0; m < matchNames.length; m++) {
|
|
195
|
+
if (mn === matchNames[m]) {
|
|
196
|
+
return comp;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (displayNames && displayNames.length) {
|
|
204
|
+
// Exact-match pass.
|
|
205
|
+
for (var i2 = 0; i2 < numComponents; i2++) {
|
|
206
|
+
var comp2 = clip.components[i2];
|
|
207
|
+
var dn2 = null;
|
|
208
|
+
try { dn2 = comp2.displayName; } catch (e) { dn2 = null; }
|
|
209
|
+
if (dn2) {
|
|
210
|
+
for (var d = 0; d < displayNames.length; d++) {
|
|
211
|
+
if (dn2 === displayNames[d]) {
|
|
212
|
+
return comp2;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Normalized-lowercase fallback pass (locale-dependent displayName).
|
|
218
|
+
for (var i3 = 0; i3 < numComponents; i3++) {
|
|
219
|
+
var comp3 = clip.components[i3];
|
|
220
|
+
var dn3 = null;
|
|
221
|
+
try { dn3 = comp3.displayName; } catch (e) { dn3 = null; }
|
|
222
|
+
if (dn3) {
|
|
223
|
+
var dn3Lower = normalizeDisplayName(dn3);
|
|
224
|
+
for (var d2 = 0; d2 < displayNames.length; d2++) {
|
|
225
|
+
if (dn3Lower === normalizeDisplayName(displayNames[d2])) {
|
|
226
|
+
return comp3;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Finds a property on a component by displayName — same exact-then-
|
|
237
|
+
// normalized-lowercase matching as findClipComponent.
|
|
238
|
+
function findComponentProperty(component, displayNames) {
|
|
239
|
+
var numProps;
|
|
240
|
+
try {
|
|
241
|
+
numProps = component.properties.numItems;
|
|
242
|
+
} catch (e) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
for (var i = 0; i < numProps; i++) {
|
|
247
|
+
var prop = component.properties[i];
|
|
248
|
+
var dn = null;
|
|
249
|
+
try { dn = prop.displayName; } catch (e) { dn = null; }
|
|
250
|
+
if (dn) {
|
|
251
|
+
for (var d = 0; d < displayNames.length; d++) {
|
|
252
|
+
if (dn === displayNames[d]) {
|
|
253
|
+
return prop;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
for (var i2 = 0; i2 < numProps; i2++) {
|
|
260
|
+
var prop2 = component.properties[i2];
|
|
261
|
+
var dn2 = null;
|
|
262
|
+
try { dn2 = prop2.displayName; } catch (e) { dn2 = null; }
|
|
263
|
+
if (dn2) {
|
|
264
|
+
var dn2Lower = normalizeDisplayName(dn2);
|
|
265
|
+
for (var d2 = 0; d2 < displayNames.length; d2++) {
|
|
266
|
+
if (dn2Lower === normalizeDisplayName(displayNames[d2])) {
|
|
267
|
+
return prop2;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Numeric/array-tolerant equality check for verifying a setValue() actually
|
|
277
|
+
// took — floats can round-trip imprecisely, and properties like
|
|
278
|
+
// Position/Anchor Point are two-element [x,y] arrays rather than scalars.
|
|
279
|
+
function valuesApproximatelyEqual(a, b, tolerance) {
|
|
280
|
+
var tol = typeof tolerance === "number" ? tolerance : 0.01;
|
|
281
|
+
|
|
282
|
+
if (a instanceof Array || b instanceof Array) {
|
|
283
|
+
if (!(a instanceof Array) || !(b instanceof Array)) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
if (a.length !== b.length) {
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
for (var i = 0; i < a.length; i++) {
|
|
290
|
+
if (!valuesApproximatelyEqual(a[i], b[i], tol)) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
298
|
+
return Math.abs(a - b) <= tol;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return a === b;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Sets one property's value, reading it before AND after the mutation.
|
|
305
|
+
// CRITICAL: undo is confirmed non-functional on this Premiere build (see
|
|
306
|
+
// the `undo` command's notes in README.md) — the returned previousValue is
|
|
307
|
+
// the caller's ONLY path to restore a property if a mutation turns out to
|
|
308
|
+
// be unwanted; callers must surface it to the caller/user, never discard
|
|
309
|
+
// it. Returns {found: false} if no property in displayNames exists on the
|
|
310
|
+
// component; otherwise {found: true, previousValue, requestedValue,
|
|
311
|
+
// newValue, verified} where verified is a tolerance-aware comparison of
|
|
312
|
+
// newValue against the requested value (see valuesApproximatelyEqual).
|
|
313
|
+
function setComponentProperty(component, displayNames, value, tolerance) {
|
|
314
|
+
var prop = findComponentProperty(component, displayNames);
|
|
315
|
+
if (!prop) {
|
|
316
|
+
return { found: false };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
var previousValue = null;
|
|
320
|
+
try { previousValue = prop.getValue(); } catch (e) { previousValue = null; }
|
|
321
|
+
|
|
322
|
+
prop.setValue(value, true);
|
|
323
|
+
|
|
324
|
+
var newValue = null;
|
|
325
|
+
try { newValue = prop.getValue(); } catch (e) { newValue = null; }
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
found: true,
|
|
329
|
+
previousValue: previousValue,
|
|
330
|
+
requestedValue: value,
|
|
331
|
+
newValue: newValue,
|
|
332
|
+
verified: valuesApproximatelyEqual(newValue, value, tolerance)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ---------------------------------------------------------------------------
|
|
337
|
+
// Shared helpers for wave-3 clip audio/flag mutation commands
|
|
338
|
+
// ---------------------------------------------------------------------------
|
|
339
|
+
|
|
340
|
+
// Makes the resolved sequence active first if it isn't already — required
|
|
341
|
+
// before any QE DOM call, which only ever operates on the active sequence
|
|
342
|
+
// tab (same pattern as get-qe-clip-info/remove-track-intervals).
|
|
343
|
+
function activateSequenceForQE(seq) {
|
|
344
|
+
if (app.project.activeSequence !== seq) {
|
|
345
|
+
app.project.activeSequence = seq;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Finds a clip's Volume component's Level property (audioVolume/Level) —
|
|
350
|
+
// shared by set-clip-volume, adjust-audio-levels, add-audio-keyframes.
|
|
351
|
+
// Returns the property object, or null if not found (e.g. not an audio
|
|
352
|
+
// clip, or this Premiere build's Volume component uses a different
|
|
353
|
+
// displayName — see PREMIERE_API_NOTES.md's locale-dependent-matching
|
|
354
|
+
// caveat, though we only probe the English name here).
|
|
355
|
+
function findVolumeLevelProperty(clip) {
|
|
356
|
+
try {
|
|
357
|
+
for (var i = 0; i < clip.components.numItems; i++) {
|
|
358
|
+
var comp = clip.components[i];
|
|
359
|
+
var compName = null;
|
|
360
|
+
var compMatch = null;
|
|
361
|
+
try { compName = comp.displayName; } catch (e) { compName = null; }
|
|
362
|
+
try { compMatch = comp.matchName; } catch (e) { compMatch = null; }
|
|
363
|
+
if (compName === "Volume" || compMatch === "audioVolume") {
|
|
364
|
+
for (var p = 0; p < comp.properties.numItems; p++) {
|
|
365
|
+
var propName = null;
|
|
366
|
+
try { propName = comp.properties[p].displayName; } catch (e) { propName = null; }
|
|
367
|
+
if (propName === "Level") {
|
|
368
|
+
return comp.properties[p];
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
} catch (e) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Finds a clip's Panner component's Balance/Pan property — shared by
|
|
380
|
+
// set-clip-pan. Component is usually "Panner" with a "Balance" property
|
|
381
|
+
// (mono-to-stereo pan); some builds/locales may expose "Pan" instead — both
|
|
382
|
+
// are probed, same defensive approach as the reference tool.
|
|
383
|
+
function findPannerProperty(clip) {
|
|
384
|
+
try {
|
|
385
|
+
for (var i = 0; i < clip.components.numItems; i++) {
|
|
386
|
+
var comp = clip.components[i];
|
|
387
|
+
var compName = null;
|
|
388
|
+
try { compName = comp.displayName; } catch (e) { compName = null; }
|
|
389
|
+
if (compName === "Panner") {
|
|
390
|
+
for (var p = 0; p < comp.properties.numItems; p++) {
|
|
391
|
+
var propName = null;
|
|
392
|
+
try { propName = comp.properties[p].displayName; } catch (e) { propName = null; }
|
|
393
|
+
if (propName === "Balance" || propName === "Pan") {
|
|
394
|
+
return comp.properties[p];
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
} catch (e) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// dB <-> linear-amplitude conversion for the audio Level property, per
|
|
406
|
+
// hetpatel's empirically-calibrated formula for this build family
|
|
407
|
+
// (PREMIERE_API_NOTES.md: "displayed 0 dB ~= internal 0.17783",
|
|
408
|
+
// linear = 10^((dB-15)/20)). leancoderkavy's own repo uses the simpler,
|
|
409
|
+
// UNCALIBRATED 10^(dB/20) instead, and ayushozha mostly passes raw dB
|
|
410
|
+
// straight through — the three reference repos do NOT agree, and none of
|
|
411
|
+
// this has been verified against our own Premiere build (no live audio
|
|
412
|
+
// clip available at authoring time). Treat every dB value that passes
|
|
413
|
+
// through these two functions as approximate until calibrated live.
|
|
414
|
+
function dbToLinearCalibrated(db) {
|
|
415
|
+
return Math.pow(10, (db - 15) / 20);
|
|
416
|
+
}
|
|
417
|
+
function linearToDbCalibrated(linear) {
|
|
418
|
+
if (!(linear > 0)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
return 20 * Math.log(linear) / Math.LN10 + 15;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// QE track item lists interleave "Empty" gap items between real clips
|
|
425
|
+
// (PREMIERE_API_NOTES.md / QE_DOM_NOTES.md) — the standard DOM's Nth clip
|
|
426
|
+
// on a track is the Nth item whose QE .type is NOT "Empty" (matches our own
|
|
427
|
+
// confirmed finding, not just the reference repos' claim). Shared by
|
|
428
|
+
// set-frame-blend and set-time-interpolation, which both need to locate the
|
|
429
|
+
// QE clip corresponding to a standard-DOM clipIndex.
|
|
430
|
+
function qeFindNthNonEmptyClip(qeTrack, clipIndex) {
|
|
431
|
+
var seen = -1;
|
|
432
|
+
var numItems = qeTrack.numItems;
|
|
433
|
+
for (var i = 0; i < numItems; i++) {
|
|
434
|
+
var item = qeTrack.getItemAt(i);
|
|
435
|
+
var itemType = null;
|
|
436
|
+
try { itemType = item.type; } catch (e) { itemType = null; }
|
|
437
|
+
if (itemType === "Empty") {
|
|
438
|
+
continue;
|
|
439
|
+
}
|
|
440
|
+
seen++;
|
|
441
|
+
if (seen === clipIndex) {
|
|
442
|
+
return item;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// ---------------------------------------------------------------------------
|
|
449
|
+
// Wave-4 effect/component helpers — shared by the effect apply/remove/copy
|
|
450
|
+
// commands (apply-effect, apply-audio-effect, remove-effect,
|
|
451
|
+
// remove-effect-by-name, remove-all-effects, color-correct, apply-lut,
|
|
452
|
+
// stabilize-clip, copy-effects-between-clips, copy-effect-values,
|
|
453
|
+
// batch-apply-effect). Builds on findClipComponent/findComponentProperty/
|
|
454
|
+
// setComponentProperty/valuesApproximatelyEqual/qeFindNthNonEmptyClip above.
|
|
455
|
+
// ---------------------------------------------------------------------------
|
|
456
|
+
|
|
457
|
+
// Resolves a standard-DOM timeline clip from trackType/trackIndex/clipIndex,
|
|
458
|
+
// with the same out-of-range error messages set-frame-blend uses. Returns
|
|
459
|
+
// {clip: <TrackItem>} on success or {error: "..."} on failure — never
|
|
460
|
+
// throws.
|
|
461
|
+
function resolveTimelineClip(seq, trackType, trackIndex, clipIndex) {
|
|
462
|
+
var trackCollection = trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
463
|
+
var numTracks = trackCollection.numTracks;
|
|
464
|
+
if (trackIndex >= numTracks) {
|
|
465
|
+
return { error: "trackIndex " + trackIndex + " is out of range — sequence has " + numTracks + " " + trackType + " track(s)" };
|
|
466
|
+
}
|
|
467
|
+
var track = trackCollection[trackIndex];
|
|
468
|
+
var numClips = track.clips.numItems;
|
|
469
|
+
if (clipIndex >= numClips) {
|
|
470
|
+
return { error: "clipIndex " + clipIndex + " is out of range — track " + trackIndex + " has " + numClips + " clip(s)" };
|
|
471
|
+
}
|
|
472
|
+
return { clip: track.clips[clipIndex] };
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Resolves the QE-DOM clip corresponding to a standard-DOM
|
|
476
|
+
// trackType/trackIndex/clipIndex, on an already-activated qeSeq (see
|
|
477
|
+
// activateSequenceForQE). Returns {qeClip, qeTrack} on success or
|
|
478
|
+
// {error: "..."} on failure — same pattern as set-frame-blend's inline
|
|
479
|
+
// lookup, factored out for reuse across the wave-4 effect commands.
|
|
480
|
+
function resolveQeClip(qeSeq, trackType, trackIndex, clipIndex) {
|
|
481
|
+
var qeTrack;
|
|
482
|
+
try {
|
|
483
|
+
qeTrack = trackType === "video" ? qeSeq.getVideoTrackAt(trackIndex) : qeSeq.getAudioTrackAt(trackIndex);
|
|
484
|
+
} catch (e) {
|
|
485
|
+
return { error: "QE track lookup failed: " + e.toString() };
|
|
486
|
+
}
|
|
487
|
+
if (!qeTrack) {
|
|
488
|
+
return { error: "QE track not found at index " + trackIndex };
|
|
489
|
+
}
|
|
490
|
+
var qeClip;
|
|
491
|
+
try {
|
|
492
|
+
qeClip = qeFindNthNonEmptyClip(qeTrack, clipIndex);
|
|
493
|
+
} catch (e) {
|
|
494
|
+
return { error: "QE clip lookup failed: " + e.toString() };
|
|
495
|
+
}
|
|
496
|
+
if (!qeClip) {
|
|
497
|
+
return { error: "could not locate the corresponding non-Empty QE clip at clipIndex " + clipIndex };
|
|
498
|
+
}
|
|
499
|
+
return { qeClip: qeClip, qeTrack: qeTrack };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Serializes a clip's components collection to a plain array of
|
|
503
|
+
// {displayName, matchName} — the "before"/"after" snapshot every mutating
|
|
504
|
+
// effect command reports per the wave-4 verification rule (read
|
|
505
|
+
// clip.components before/after, report counts AND names).
|
|
506
|
+
function serializeClipComponents(clip) {
|
|
507
|
+
var out = [];
|
|
508
|
+
try {
|
|
509
|
+
var numComponents = clip.components.numItems;
|
|
510
|
+
for (var i = 0; i < numComponents; i++) {
|
|
511
|
+
var comp = clip.components[i];
|
|
512
|
+
var dn = null;
|
|
513
|
+
var mn = null;
|
|
514
|
+
try { dn = comp.displayName; } catch (e) { dn = null; }
|
|
515
|
+
try { mn = comp.matchName; } catch (e) { mn = null; }
|
|
516
|
+
out.push({ displayName: dn, matchName: mn });
|
|
517
|
+
}
|
|
518
|
+
} catch (e) {
|
|
519
|
+
// fall through — caller sees an empty array, not a thrown error
|
|
520
|
+
}
|
|
521
|
+
return out;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Looks up a video effect by name in the QE catalog — getVideoEffectByName
|
|
525
|
+
// first (per PREMIERE_API_NOTES.md's documented "universal dance"), falling
|
|
526
|
+
// back to a linear scan of getVideoEffectList() in case the by-name lookup
|
|
527
|
+
// itself is unavailable/unreliable on this build. Returns the QE effect
|
|
528
|
+
// object, or null if not found by either path.
|
|
529
|
+
function findQeVideoEffectByName(name) {
|
|
530
|
+
try {
|
|
531
|
+
var fx = qe.project.getVideoEffectByName(name);
|
|
532
|
+
if (fx) {
|
|
533
|
+
return fx;
|
|
534
|
+
}
|
|
535
|
+
} catch (e) {
|
|
536
|
+
// fall through to list scan
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
var list = qe.project.getVideoEffectList();
|
|
540
|
+
for (var i = 0; i < list.numItems; i++) {
|
|
541
|
+
if (list[i].name === name) {
|
|
542
|
+
return list[i];
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} catch (e) {
|
|
546
|
+
// fall through — caller reports "not found"
|
|
547
|
+
}
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Audio counterpart of findQeVideoEffectByName.
|
|
552
|
+
function findQeAudioEffectByName(name) {
|
|
553
|
+
try {
|
|
554
|
+
var fx = qe.project.getAudioEffectByName(name);
|
|
555
|
+
if (fx) {
|
|
556
|
+
return fx;
|
|
557
|
+
}
|
|
558
|
+
} catch (e) {
|
|
559
|
+
// fall through to list scan
|
|
560
|
+
}
|
|
561
|
+
try {
|
|
562
|
+
var list = qe.project.getAudioEffectList();
|
|
563
|
+
for (var i = 0; i < list.numItems; i++) {
|
|
564
|
+
if (list[i].name === name) {
|
|
565
|
+
return list[i];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
} catch (e) {
|
|
569
|
+
// fall through — caller reports "not found"
|
|
570
|
+
}
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// Built-in components no removal command should ever touch — checked by
|
|
575
|
+
// BOTH matchName (reliable, locale-independent) and displayName (fallback,
|
|
576
|
+
// locale-dependent) per remove-effect's "protect the built-ins" rule.
|
|
577
|
+
function isProtectedBuiltinComponent(comp) {
|
|
578
|
+
var mn = null;
|
|
579
|
+
var dn = null;
|
|
580
|
+
try { mn = comp.matchName; } catch (e) { mn = null; }
|
|
581
|
+
try { dn = comp.displayName; } catch (e) { dn = null; }
|
|
582
|
+
|
|
583
|
+
var protectedMatchNames = ["AE.ADBE Motion", "AE.ADBE Opacity"];
|
|
584
|
+
for (var i = 0; i < protectedMatchNames.length; i++) {
|
|
585
|
+
if (mn === protectedMatchNames[i]) {
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
var protectedDisplayNames = ["Motion", "Opacity"];
|
|
590
|
+
for (var j = 0; j < protectedDisplayNames.length; j++) {
|
|
591
|
+
if (dn === protectedDisplayNames[j]) {
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Intrinsic/non-effect component display names — copy-effects-between-clips
|
|
599
|
+
// skips these when no effectName filter narrows the copy to one effect
|
|
600
|
+
// (matches leancoderkavy's clipboard.ts intrinsic list).
|
|
601
|
+
var INTRINSIC_COMPONENT_DISPLAY_NAMES = ["Motion", "Opacity", "Time Remapping", "Volume", "Channel Volume", "Panner"];
|
|
602
|
+
|
|
603
|
+
function isIntrinsicComponentDisplayName(name) {
|
|
604
|
+
for (var i = 0; i < INTRINSIC_COMPONENT_DISPLAY_NAMES.length; i++) {
|
|
605
|
+
if (name === INTRINSIC_COMPONENT_DISPLAY_NAMES[i]) {
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Finds (and applies via QE if missing) the Lumetri Color component on a
|
|
613
|
+
// clip — shared by color-correct and apply-lut, both of which need it
|
|
614
|
+
// present before setting properties. seq must already be the clip's own
|
|
615
|
+
// sequence; QE will be activated on it if the effect needs applying.
|
|
616
|
+
// Returns {component, applied} on success (applied = true if this call had
|
|
617
|
+
// to add it) or {error: "..."} on failure.
|
|
618
|
+
function ensureLumetriColorComponent(seq, trackType, trackIndex, clipIndex, clip) {
|
|
619
|
+
var existing = findClipComponent(clip, ["AE.ADBE Lumetri"], ["Lumetri Color"]);
|
|
620
|
+
if (existing) {
|
|
621
|
+
return { component: existing, applied: false };
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
try {
|
|
625
|
+
ensureQEEnabled();
|
|
626
|
+
activateSequenceForQE(seq);
|
|
627
|
+
} catch (e) {
|
|
628
|
+
return { error: "app.enableQE()/sequence activation failed: " + e.toString() };
|
|
629
|
+
}
|
|
630
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
631
|
+
return { error: "QE DOM not available after enableQE()" };
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
var qeSeq;
|
|
635
|
+
try {
|
|
636
|
+
qeSeq = qe.project.getActiveSequence();
|
|
637
|
+
} catch (e) {
|
|
638
|
+
return { error: "qe.project.getActiveSequence() failed: " + e.toString() };
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
var qeResolved = resolveQeClip(qeSeq, trackType, trackIndex, clipIndex);
|
|
642
|
+
if (qeResolved.error) {
|
|
643
|
+
return { error: qeResolved.error };
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
var fx = findQeVideoEffectByName("Lumetri Color");
|
|
647
|
+
if (!fx) {
|
|
648
|
+
return { error: "Lumetri Color effect not found in this Premiere install's QE effect catalog" };
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
try {
|
|
652
|
+
qeResolved.qeClip.addVideoEffect(fx);
|
|
653
|
+
} catch (e) {
|
|
654
|
+
return { error: "qeClip.addVideoEffect(Lumetri Color) failed: " + e.toString() };
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
var reFound = findClipComponent(clip, ["AE.ADBE Lumetri"], ["Lumetri Color"]);
|
|
658
|
+
if (!reFound) {
|
|
659
|
+
return { error: "Lumetri Color was applied via QE but could not be re-found on the standard-DOM clip afterward" };
|
|
660
|
+
}
|
|
661
|
+
return { component: reFound, applied: true };
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// ---------------------------------------------------------------------------
|
|
665
|
+
// Keyframe/effect-property helpers — shared by wave-4's get-effect-properties,
|
|
666
|
+
// set-effect-property, get-keyframes, add-keyframe, remove-keyframe,
|
|
667
|
+
// remove-keyframe-range, set-keyframe-interpolation, get-value-at-time, and
|
|
668
|
+
// set-color-value. Per PREMIERE_API_NOTES.md's Property API section: a
|
|
669
|
+
// property's key TIME argument is Time objects on some Premiere builds and
|
|
670
|
+
// plain seconds on others (version drift) — tryTimeForms() below tries
|
|
671
|
+
// ticksString, then a Time object, then a raw seconds number, recording an
|
|
672
|
+
// `attempts` array so callers can see exactly what worked, same spirit as
|
|
673
|
+
// index.jsx's own trySetSequenceRange(). Component lookup for these commands
|
|
674
|
+
// is deliberately GENERIC (any component, not just Motion/Opacity) — callers
|
|
675
|
+
// pass an arbitrary componentName as BOTH the matchName and displayName
|
|
676
|
+
// candidate list to the existing findClipComponent() helper above.
|
|
677
|
+
// ---------------------------------------------------------------------------
|
|
678
|
+
|
|
679
|
+
function secondsToTicksString(seconds) {
|
|
680
|
+
return String(Math.round(seconds * TICKS_PER_SECOND));
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function secondsToTimeObject(seconds) {
|
|
684
|
+
var t = new Time();
|
|
685
|
+
t.seconds = seconds;
|
|
686
|
+
return t;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// Calls fn(timeArg) trying, in order: a ticks string, a Time object, then a
|
|
690
|
+
// raw seconds number — stopping at the first form fn() doesn't throw on.
|
|
691
|
+
// fn's return value (if any) is carried through as `result`. Returns
|
|
692
|
+
// {success, result?, attempts, formUsed?} — attempts is always populated,
|
|
693
|
+
// even on total failure, so the caller can report exactly what was tried.
|
|
694
|
+
function tryTimeForms(seconds, fn) {
|
|
695
|
+
var attempts = [];
|
|
696
|
+
var forms = [
|
|
697
|
+
{ label: "ticksString", value: secondsToTicksString(seconds) },
|
|
698
|
+
{ label: "TimeObject", value: secondsToTimeObject(seconds) },
|
|
699
|
+
{ label: "seconds", value: seconds }
|
|
700
|
+
];
|
|
701
|
+
for (var i = 0; i < forms.length; i++) {
|
|
702
|
+
try {
|
|
703
|
+
var result = fn(forms[i].value);
|
|
704
|
+
attempts.push({ form: forms[i].label, success: true });
|
|
705
|
+
return { success: true, result: result, attempts: attempts, formUsed: forms[i].label };
|
|
706
|
+
} catch (e) {
|
|
707
|
+
attempts.push({ form: forms[i].label, success: false, error: e.toString() });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return { success: false, attempts: attempts };
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Normalizes a key time value returned by prop.getKeys()/etc. to seconds.
|
|
714
|
+
// Per PREMIERE_API_NOTES.md, key times are DISPUTED across builds: Time
|
|
715
|
+
// objects (handled by the existing timeValueToSeconds()), or — per some
|
|
716
|
+
// repos/builds — a raw ticks number/string, or a raw seconds number/string.
|
|
717
|
+
// A raw numeric/string value is heuristically treated as ticks if it's
|
|
718
|
+
// larger than 1,000,000 (no realistic sequence position is that many
|
|
719
|
+
// seconds — over 11 days — while ticks routinely exceed it), else as plain
|
|
720
|
+
// seconds. This heuristic is UNVERIFIED against a live keyframed property.
|
|
721
|
+
function keyTimeToSeconds(keyTime) {
|
|
722
|
+
if (keyTime === null || typeof keyTime === "undefined") {
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
if (typeof keyTime === "number") {
|
|
726
|
+
return keyTime > 1000000 ? (keyTime / TICKS_PER_SECOND) : keyTime;
|
|
727
|
+
}
|
|
728
|
+
if (typeof keyTime === "string") {
|
|
729
|
+
var n = Number(keyTime);
|
|
730
|
+
if (isNaN(n)) {
|
|
731
|
+
return null;
|
|
732
|
+
}
|
|
733
|
+
return n > 1000000 ? (n / TICKS_PER_SECOND) : n;
|
|
734
|
+
}
|
|
735
|
+
return timeValueToSeconds(keyTime);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// ---------------------------------------------------------------------------
|
|
739
|
+
// Shared helper for wave-4 transition mutation commands (add-transition,
|
|
740
|
+
// batch-add-transitions) — see PREMIERE_API_NOTES.md's "Transitions (QE
|
|
741
|
+
// only)" line: qe.project.getVideoTransitionByName(name) resolves the
|
|
742
|
+
// transition, then addTransition() is called with a DISPUTED argument
|
|
743
|
+
// count/duration format across the three reference repos (3-7 args;
|
|
744
|
+
// "frames:00" timecode string vs seconds-string vs ticks string), on
|
|
745
|
+
// EITHER the QE clip or the QE track depending on which repo you read.
|
|
746
|
+
// Rather than pick one, every plausible form is tried in turn and success
|
|
747
|
+
// is verified the only reliable way available: a numItems delta on the
|
|
748
|
+
// STANDARD DOM's track.transitions collection (QE addTransition's own
|
|
749
|
+
// return value is not trustworthy — same lesson as export-frame's
|
|
750
|
+
// exportFramePNG). Video-only: no reference repo demonstrates an
|
|
751
|
+
// audio-transition "add" API, only add-transition's video enumeration
|
|
752
|
+
// (list-available-transitions) and audio's own list-only command.
|
|
753
|
+
// ---------------------------------------------------------------------------
|
|
754
|
+
|
|
755
|
+
function ppbGetTrackTransitionsCount(track) {
|
|
756
|
+
try {
|
|
757
|
+
return track.transitions.numItems;
|
|
758
|
+
} catch (e) {
|
|
759
|
+
return null;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function ppbReadLastTransitionName(track) {
|
|
764
|
+
try {
|
|
765
|
+
var n = track.transitions.numItems;
|
|
766
|
+
if (n <= 0) {
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
var t = track.transitions[n - 1];
|
|
770
|
+
try { return t.name; } catch (e) { return null; }
|
|
771
|
+
} catch (e2) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Applies one transition to one clip's start/end, addressed the same way
|
|
777
|
+
// as get-full-clip-info (trackIndex/clipIndex on seq.videoTracks — video
|
|
778
|
+
// only). `transitionQE` is the already-resolved QE transition object (or
|
|
779
|
+
// null for "default transition", per ayushozha's addTransition(null, true,
|
|
780
|
+
// "1.0") convention). Returns a plain object — never throws; every
|
|
781
|
+
// failure mode is captured in the returned shape so callers (add-
|
|
782
|
+
// transition, batch-add-transitions) can report per-clip results
|
|
783
|
+
// uniformly.
|
|
784
|
+
function ppbApplyTransitionToClip(seq, trackIndex, clipIndex, transitionQE, atEnd, durationSeconds) {
|
|
785
|
+
var out = {
|
|
786
|
+
trackIndex: trackIndex,
|
|
787
|
+
clipIndex: clipIndex,
|
|
788
|
+
clipName: null,
|
|
789
|
+
previousCount: null,
|
|
790
|
+
newCount: null,
|
|
791
|
+
verified: false,
|
|
792
|
+
attempts: [],
|
|
793
|
+
succeededWithArgs: null,
|
|
794
|
+
addedTransitionName: null,
|
|
795
|
+
error: null
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
var numTracks;
|
|
799
|
+
try { numTracks = seq.videoTracks.numTracks; } catch (e) { numTracks = 0; }
|
|
800
|
+
if (trackIndex >= numTracks) {
|
|
801
|
+
out.error = "trackIndex " + trackIndex + " is out of range — sequence has " + numTracks + " video track(s)";
|
|
802
|
+
return out;
|
|
803
|
+
}
|
|
804
|
+
var track = seq.videoTracks[trackIndex];
|
|
805
|
+
var numClips;
|
|
806
|
+
try { numClips = track.clips.numItems; } catch (e2) { numClips = 0; }
|
|
807
|
+
if (clipIndex >= numClips) {
|
|
808
|
+
out.error = "clipIndex " + clipIndex + " is out of range — track " + trackIndex + " has " + numClips + " clip(s)";
|
|
809
|
+
return out;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
var clip = track.clips[clipIndex];
|
|
813
|
+
try { out.clipName = clip.name; } catch (e3) { out.clipName = null; }
|
|
814
|
+
|
|
815
|
+
out.previousCount = ppbGetTrackTransitionsCount(track);
|
|
816
|
+
|
|
817
|
+
try {
|
|
818
|
+
ensureQEEnabled();
|
|
819
|
+
activateSequenceForQE(seq);
|
|
820
|
+
} catch (e4) {
|
|
821
|
+
out.error = "app.enableQE()/sequence activation failed: " + e4.toString();
|
|
822
|
+
return out;
|
|
823
|
+
}
|
|
824
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
825
|
+
out.error = "QE DOM not available after enableQE()";
|
|
826
|
+
return out;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
var qeSeq, qeTrack, qeClip;
|
|
830
|
+
try {
|
|
831
|
+
qeSeq = qe.project.getActiveSequence();
|
|
832
|
+
qeTrack = qeSeq.getVideoTrackAt(trackIndex);
|
|
833
|
+
qeClip = qeFindNthNonEmptyClip(qeTrack, clipIndex);
|
|
834
|
+
} catch (e5) {
|
|
835
|
+
out.error = "QE track/clip lookup failed: " + e5.toString();
|
|
836
|
+
return out;
|
|
837
|
+
}
|
|
838
|
+
if (!qeTrack || !qeClip) {
|
|
839
|
+
out.error = "could not locate the corresponding QE track/clip";
|
|
840
|
+
return out;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
var secondsStr = String(durationSeconds);
|
|
844
|
+
var ticksStr = String(Math.round(durationSeconds * TICKS_PER_SECOND));
|
|
845
|
+
var cutTicksStr = null;
|
|
846
|
+
try { cutTicksStr = (atEnd ? clip.end.ticks : clip.start.ticks).toString(); } catch (e6) { cutTicksStr = null; }
|
|
847
|
+
|
|
848
|
+
function attempt(label, fn) {
|
|
849
|
+
if (out.verified) {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
var entry = { form: label };
|
|
853
|
+
try {
|
|
854
|
+
fn();
|
|
855
|
+
entry.success = true;
|
|
856
|
+
} catch (e7) {
|
|
857
|
+
entry.success = false;
|
|
858
|
+
entry.error = e7.toString();
|
|
859
|
+
out.attempts.push(entry);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
var newCount = ppbGetTrackTransitionsCount(track);
|
|
863
|
+
if (newCount !== null && out.previousCount !== null && newCount > out.previousCount) {
|
|
864
|
+
entry.verifiedCount = newCount;
|
|
865
|
+
out.verified = true;
|
|
866
|
+
out.newCount = newCount;
|
|
867
|
+
out.succeededWithArgs = label;
|
|
868
|
+
out.addedTransitionName = ppbReadLastTransitionName(track);
|
|
869
|
+
} else {
|
|
870
|
+
entry.note = "call did not throw, but transitions count did not increase — treating as unverified";
|
|
871
|
+
}
|
|
872
|
+
out.attempts.push(entry);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// qeClip-level forms (per PREMIERE_API_NOTES.md's headline signature).
|
|
876
|
+
attempt("qeClip.addTransition(tr, atEnd, secondsString)", function () {
|
|
877
|
+
qeClip.addTransition(transitionQE, atEnd, secondsStr);
|
|
878
|
+
});
|
|
879
|
+
attempt("qeClip.addTransition(tr, atEnd, ticksString)", function () {
|
|
880
|
+
qeClip.addTransition(transitionQE, atEnd, ticksStr);
|
|
881
|
+
});
|
|
882
|
+
attempt("qeClip.addTransition(tr, atEnd, secondsString, \"0\")", function () {
|
|
883
|
+
qeClip.addTransition(transitionQE, atEnd, secondsStr, "0");
|
|
884
|
+
});
|
|
885
|
+
attempt("qeClip.addTransition(tr, atEnd, ticksString, \"0\", false)", function () {
|
|
886
|
+
qeClip.addTransition(transitionQE, atEnd, ticksStr, "0", false);
|
|
887
|
+
});
|
|
888
|
+
attempt("qeClip.addTransition(tr, atEnd, durationSecondsNumber)", function () {
|
|
889
|
+
qeClip.addTransition(transitionQE, atEnd, durationSeconds);
|
|
890
|
+
});
|
|
891
|
+
// qeTrack-level forms (leancoderkavy's own reference implementation —
|
|
892
|
+
// cut-point ticks + duration ticks + alignment + reverse booleans).
|
|
893
|
+
if (cutTicksStr !== null) {
|
|
894
|
+
attempt("qeTrack.addTransition(tr, atEnd, cutTicks, durationTicks, \"0\", false)", function () {
|
|
895
|
+
qeTrack.addTransition(transitionQE, atEnd, cutTicksStr, ticksStr, "0", false);
|
|
896
|
+
});
|
|
897
|
+
attempt("qeTrack.addTransition(tr, atEnd, cutTicks, durationSeconds, \"0\", false)", function () {
|
|
898
|
+
qeTrack.addTransition(transitionQE, atEnd, cutTicksStr, secondsStr, "0", false);
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
if (!out.verified) {
|
|
903
|
+
out.error = "could not add the transition with any known argument form — see attempts";
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
return out;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// ---------------------------------------------------------------------------
|
|
910
|
+
// Lazy command dispatch
|
|
911
|
+
// ---------------------------------------------------------------------------
|
|
912
|
+
|
|
913
|
+
// Command name → { file under host/commands/, ppb_ function it defines }.
|
|
914
|
+
// To add a command: create host/commands/<name>.jsx defining the function,
|
|
915
|
+
// add a line here, and add the command name to main.js's ALLOWED_COMMANDS.
|
|
916
|
+
var PPB_COMMANDS = {
|
|
917
|
+
"create-sequence": { file: "create-sequence.jsx", fn: "ppb_createSequence" },
|
|
918
|
+
"extract-audio-track": { file: "extract-audio-track.jsx", fn: "ppb_extractAudioTrack" },
|
|
919
|
+
"remove-track-intervals": { file: "remove-track-intervals.jsx", fn: "ppb_removeTrackIntervals" },
|
|
920
|
+
"export-frame": { file: "export-frame.jsx", fn: "ppb_exportFrame" },
|
|
921
|
+
"get-project-info": { file: "get-project-info.jsx", fn: "ppb_getProjectInfo" },
|
|
922
|
+
"list-project-items": { file: "list-project-items.jsx", fn: "ppb_listProjectItems" },
|
|
923
|
+
"get-full-project-overview": { file: "get-full-project-overview.jsx", fn: "ppb_getFullProjectOverview" },
|
|
924
|
+
"search-project-items": { file: "search-project-items.jsx", fn: "ppb_searchProjectItems" },
|
|
925
|
+
"get-active-sequence": { file: "get-active-sequence.jsx", fn: "ppb_getActiveSequence" },
|
|
926
|
+
"get-full-sequence-info": { file: "get-full-sequence-info.jsx", fn: "ppb_getFullSequenceInfo" },
|
|
927
|
+
"get-full-clip-info": { file: "get-full-clip-info.jsx", fn: "ppb_getFullClipInfo" },
|
|
928
|
+
"get-timeline-summary": { file: "get-timeline-summary.jsx", fn: "ppb_getTimelineSummary" },
|
|
929
|
+
"set-clip-volume": { file: "set-clip-volume.jsx", fn: "ppb_setClipVolume" },
|
|
930
|
+
"set-clip-pan": { file: "set-clip-pan.jsx", fn: "ppb_setClipPan" },
|
|
931
|
+
"adjust-audio-levels": { file: "adjust-audio-levels.jsx", fn: "ppb_adjustAudioLevels" },
|
|
932
|
+
"add-audio-keyframes": { file: "add-audio-keyframes.jsx", fn: "ppb_addAudioKeyframes" },
|
|
933
|
+
"rename-clip": { file: "rename-clip.jsx", fn: "ppb_renameClip" },
|
|
934
|
+
"batch-rename-clips": { file: "batch-rename-clips.jsx", fn: "ppb_batchRenameClips" },
|
|
935
|
+
"set-clip-enabled": { file: "set-clip-enabled.jsx", fn: "ppb_setClipEnabled" },
|
|
936
|
+
"batch-set-clips-enabled": { file: "batch-set-clips-enabled.jsx", fn: "ppb_batchSetClipsEnabled" },
|
|
937
|
+
"set-frame-blend": { file: "set-frame-blend.jsx", fn: "ppb_setFrameBlend" },
|
|
938
|
+
"set-time-interpolation": { file: "set-time-interpolation.jsx", fn: "ppb_setTimeInterpolation" },
|
|
939
|
+
"set-clip-properties": { file: "set-clip-properties.jsx", fn: "ppb_setClipProperties" },
|
|
940
|
+
"set-item-metadata": { file: "set-item-metadata.jsx", fn: "ppb_setItemMetadata" },
|
|
941
|
+
"set-color-label": { file: "set-color-label.jsx", fn: "ppb_setColorLabel" },
|
|
942
|
+
"set-footage-interpretation": { file: "set-footage-interpretation.jsx", fn: "ppb_setFootageInterpretation" },
|
|
943
|
+
"set-xmp-metadata": { file: "set-xmp-metadata.jsx", fn: "ppb_setXmpMetadata" },
|
|
944
|
+
"get-effect-properties": { file: "get-effect-properties.jsx", fn: "ppb_getEffectProperties" },
|
|
945
|
+
"set-effect-property": { file: "set-effect-property.jsx", fn: "ppb_setEffectProperty" },
|
|
946
|
+
"get-keyframes": { file: "get-keyframes.jsx", fn: "ppb_getKeyframes" },
|
|
947
|
+
"add-keyframe": { file: "add-keyframe.jsx", fn: "ppb_addKeyframe" },
|
|
948
|
+
"remove-keyframe": { file: "remove-keyframe.jsx", fn: "ppb_removeKeyframe" },
|
|
949
|
+
"remove-keyframe-range": { file: "remove-keyframe-range.jsx", fn: "ppb_removeKeyframeRange" },
|
|
950
|
+
"set-keyframe-interpolation": { file: "set-keyframe-interpolation.jsx", fn: "ppb_setKeyframeInterpolation" },
|
|
951
|
+
"get-value-at-time": { file: "get-value-at-time.jsx", fn: "ppb_getValueAtTime" },
|
|
952
|
+
"set-color-value": { file: "set-color-value.jsx", fn: "ppb_setColorValue" },
|
|
953
|
+
"add-transition": { file: "add-transition.jsx", fn: "ppb_addTransition" },
|
|
954
|
+
"batch-add-transitions": { file: "batch-add-transitions.jsx", fn: "ppb_batchAddTransitions" },
|
|
955
|
+
"remove-transition": { file: "remove-transition.jsx", fn: "ppb_removeTransition" },
|
|
956
|
+
"ripple-delete-clip": { file: "ripple-delete-clip.jsx", fn: "ppb_rippleDeleteClip" },
|
|
957
|
+
"roll-edit": { file: "roll-edit.jsx", fn: "ppb_rollEdit" },
|
|
958
|
+
"slide-edit": { file: "slide-edit.jsx", fn: "ppb_slideEdit" },
|
|
959
|
+
"slip-edit": { file: "slip-edit.jsx", fn: "ppb_slipEdit" },
|
|
960
|
+
"move-clip-to-track": { file: "move-clip-to-track.jsx", fn: "ppb_moveClipToTrack" },
|
|
961
|
+
"reverse-clip": { file: "reverse-clip.jsx", fn: "ppb_reverseClip" },
|
|
962
|
+
"link-selection": { file: "link-selection.jsx", fn: "ppb_linkSelection" },
|
|
963
|
+
"unlink-selection": { file: "unlink-selection.jsx", fn: "ppb_unlinkSelection" },
|
|
964
|
+
"overwrite-clip-at": { file: "overwrite-clip-at.jsx", fn: "ppb_overwriteClipAt" },
|
|
965
|
+
"razor-all-tracks": { file: "razor-all-tracks.jsx", fn: "ppb_razorAllTracks" },
|
|
966
|
+
"set-item-in-out": { file: "set-item-in-out.jsx", fn: "ppb_setItemInOut" },
|
|
967
|
+
"clear-item-in-out": { file: "clear-item-in-out.jsx", fn: "ppb_clearItemInOut" },
|
|
968
|
+
"clear-sequence-in-out": { file: "clear-sequence-in-out.jsx", fn: "ppb_clearSequenceInOut" },
|
|
969
|
+
"remove-selected-clips": { file: "remove-selected-clips.jsx", fn: "ppb_removeSelectedClips" },
|
|
970
|
+
"lift-selection": { file: "lift-selection.jsx", fn: "ppb_liftSelection" },
|
|
971
|
+
"extract-selection": { file: "extract-selection.jsx", fn: "ppb_extractSelection" },
|
|
972
|
+
"nest-clips": { file: "nest-clips.jsx", fn: "ppb_nestClips" },
|
|
973
|
+
"freeze-frame": { file: "freeze-frame.jsx", fn: "ppb_freezeFrame" },
|
|
974
|
+
"match-frame": { file: "match-frame.jsx", fn: "ppb_matchFrame" },
|
|
975
|
+
"add-adjustment-layer": { file: "add-adjustment-layer.jsx", fn: "ppb_addAdjustmentLayer" },
|
|
976
|
+
"unnest-sequence": { file: "unnest-sequence.jsx", fn: "ppb_unnestSequence" },
|
|
977
|
+
"save-project": { file: "save-project.jsx", fn: "ppb_saveProject" },
|
|
978
|
+
"save-project-as": { file: "save-project-as.jsx", fn: "ppb_saveProjectAs" },
|
|
979
|
+
"open-project": { file: "open-project.jsx", fn: "ppb_openProject" },
|
|
980
|
+
"set-active-sequence": { file: "set-active-sequence.jsx", fn: "ppb_setActiveSequence" },
|
|
981
|
+
"find-items-by-media-path": { file: "find-items-by-media-path.jsx", fn: "ppb_findItemsByMediaPath" },
|
|
982
|
+
"create-smart-bin": { file: "create-smart-bin.jsx", fn: "ppb_createSmartBin" },
|
|
983
|
+
"add-custom-metadata-field": { file: "add-custom-metadata-field.jsx", fn: "ppb_addCustomMetadataField" },
|
|
984
|
+
"import-sequences-from-project": { file: "import-sequences-from-project.jsx", fn: "ppb_importSequencesFromProject" },
|
|
985
|
+
"import-fcp-xml": { file: "import-fcp-xml.jsx", fn: "ppb_importFcpXml" },
|
|
986
|
+
"import-ae-comps": { file: "import-ae-comps.jsx", fn: "ppb_importAeComps" },
|
|
987
|
+
"create-bars-and-tone": { file: "create-bars-and-tone.jsx", fn: "ppb_createBarsAndTone" },
|
|
988
|
+
"set-transcode-on-ingest": { file: "set-transcode-on-ingest.jsx", fn: "ppb_setTranscodeOnIngest" },
|
|
989
|
+
"set-project-panel-metadata": { file: "set-project-panel-metadata.jsx", fn: "ppb_setProjectPanelMetadata" },
|
|
990
|
+
"get-graphics-white-luminance": { file: "get-graphics-white-luminance.jsx", fn: "ppb_getGraphicsWhiteLuminance" },
|
|
991
|
+
"set-graphics-white-luminance": { file: "set-graphics-white-luminance.jsx", fn: "ppb_setGraphicsWhiteLuminance" },
|
|
992
|
+
"duplicate-sequence": { file: "duplicate-sequence.jsx", fn: "ppb_duplicateSequence" },
|
|
993
|
+
"set-sequence-settings": { file: "set-sequence-settings.jsx", fn: "ppb_setSequenceSettings" },
|
|
994
|
+
"create-subsequence": { file: "create-subsequence.jsx", fn: "ppb_createSubsequence" },
|
|
995
|
+
"auto-reframe-sequence": { file: "auto-reframe-sequence.jsx", fn: "ppb_autoReframeSequence" },
|
|
996
|
+
"create-sequence-from-preset": { file: "create-sequence-from-preset.jsx", fn: "ppb_createSequenceFromPreset" },
|
|
997
|
+
"create-sequence-from-clips": { file: "create-sequence-from-clips.jsx", fn: "ppb_createSequenceFromClips" },
|
|
998
|
+
"attach-custom-property": { file: "attach-custom-property.jsx", fn: "ppb_attachCustomProperty" },
|
|
999
|
+
"close-sequence": { file: "close-sequence.jsx", fn: "ppb_closeSequence" },
|
|
1000
|
+
"export-sequence-as-project": { file: "export-sequence-as-project.jsx", fn: "ppb_exportSequenceAsProject" },
|
|
1001
|
+
"scene-edit-detection": { file: "scene-edit-detection.jsx", fn: "ppb_sceneEditDetection" },
|
|
1002
|
+
"export-sequence": { file: "export-sequence.jsx", fn: "ppb_exportSequence" },
|
|
1003
|
+
"export-fcp-xml": { file: "export-fcp-xml.jsx", fn: "ppb_exportFcpXml" },
|
|
1004
|
+
"export-aaf": { file: "export-aaf.jsx", fn: "ppb_exportAaf" },
|
|
1005
|
+
"export-omf": { file: "export-omf.jsx", fn: "ppb_exportOmf" },
|
|
1006
|
+
"add-to-render-queue": { file: "add-to-render-queue.jsx", fn: "ppb_addToRenderQueue" },
|
|
1007
|
+
"create-subclip": { file: "create-subclip.jsx", fn: "ppb_createSubclip" },
|
|
1008
|
+
"encode-project-item": { file: "encode-project-item.jsx", fn: "ppb_encodeProjectItem" },
|
|
1009
|
+
"encode-file": { file: "encode-file.jsx", fn: "ppb_encodeFile" },
|
|
1010
|
+
"manage-proxies": { file: "manage-proxies.jsx", fn: "ppb_manageProxies" },
|
|
1011
|
+
"open-in-source": { file: "open-in-source.jsx", fn: "ppb_openInSource" },
|
|
1012
|
+
"close-source-monitor": { file: "close-source-monitor.jsx", fn: "ppb_closeSourceMonitor" },
|
|
1013
|
+
"close-all-source-clips": { file: "close-all-source-clips.jsx", fn: "ppb_closeAllSourceClips" },
|
|
1014
|
+
"set-source-in-out": { file: "set-source-in-out.jsx", fn: "ppb_setSourceInOut" },
|
|
1015
|
+
"insert-from-source": { file: "insert-from-source.jsx", fn: "ppb_insertFromSource" },
|
|
1016
|
+
"overwrite-from-source": { file: "overwrite-from-source.jsx", fn: "ppb_overwriteFromSource" },
|
|
1017
|
+
"add-text-overlay": { file: "add-text-overlay.jsx", fn: "ppb_addTextOverlay" },
|
|
1018
|
+
"import-mogrt": { file: "import-mogrt.jsx", fn: "ppb_importMogrt" },
|
|
1019
|
+
"import-mogrt-from-library": { file: "import-mogrt-from-library.jsx", fn: "ppb_importMogrtFromLibrary" },
|
|
1020
|
+
"get-mogrt-component": { file: "get-mogrt-component.jsx", fn: "ppb_getMogrtComponent" },
|
|
1021
|
+
"create-caption-track": { file: "create-caption-track.jsx", fn: "ppb_createCaptionTrack" },
|
|
1022
|
+
"replace-clip-media": { file: "replace-clip-media.jsx", fn: "ppb_replaceClipMedia" },
|
|
1023
|
+
"debug-qe-inspect": { file: "debug-qe-inspect.jsx", fn: "ppb_debugQeInspect" },
|
|
1024
|
+
"debug-qe-try-mutate": { file: "debug-qe-try-mutate.jsx", fn: "ppb_debugQeTryMutate" },
|
|
1025
|
+
"get-premiere-state": { file: "get-premiere-state.jsx", fn: "ppb_getPremiereState" },
|
|
1026
|
+
"inspect-dom-object": { file: "inspect-dom-object.jsx", fn: "ppb_inspectDomObject" },
|
|
1027
|
+
"get-open-projects": { file: "get-open-projects.jsx", fn: "ppb_getOpenProjects" },
|
|
1028
|
+
"set-active-project": { file: "set-active-project.jsx", fn: "ppb_setActiveProject" },
|
|
1029
|
+
"move-playhead": { file: "move-playhead.jsx", fn: "ppb_movePlayhead" },
|
|
1030
|
+
"get-work-area": { file: "get-work-area.jsx", fn: "ppb_getWorkArea" },
|
|
1031
|
+
"set-work-area": { file: "set-work-area.jsx", fn: "ppb_setWorkArea" },
|
|
1032
|
+
"get-sequence-in-out": { file: "get-sequence-in-out.jsx", fn: "ppb_getSequenceInOut" },
|
|
1033
|
+
"set-sequence-in-out": { file: "set-sequence-in-out.jsx", fn: "ppb_setSequenceInOut" },
|
|
1034
|
+
"is-work-area-enabled": { file: "is-work-area-enabled.jsx", fn: "ppb_isWorkAreaEnabled" },
|
|
1035
|
+
"get-export-file-extension": { file: "get-export-file-extension.jsx", fn: "ppb_getExportFileExtension" },
|
|
1036
|
+
"get-workspaces": { file: "get-workspaces.jsx", fn: "ppb_getWorkspaces" },
|
|
1037
|
+
"set-workspace": { file: "set-workspace.jsx", fn: "ppb_setWorkspace" },
|
|
1038
|
+
"play-timeline": { file: "play-timeline.jsx", fn: "ppb_playTimeline" },
|
|
1039
|
+
"stop-playback": { file: "stop-playback.jsx", fn: "ppb_stopPlayback" },
|
|
1040
|
+
"play-source-monitor": { file: "play-source-monitor.jsx", fn: "ppb_playSourceMonitor" },
|
|
1041
|
+
"get-source-monitor-position": { file: "get-source-monitor-position.jsx", fn: "ppb_getSourceMonitorPosition" },
|
|
1042
|
+
"get-version-info": { file: "get-version-info.jsx", fn: "ppb_getVersionInfo" },
|
|
1043
|
+
"get-bin-contents": { file: "get-bin-contents.jsx", fn: "ppb_getBinContents" },
|
|
1044
|
+
"get-project-item-info": { file: "get-project-item-info.jsx", fn: "ppb_getProjectItemInfo" },
|
|
1045
|
+
"get-timeline-gaps": { file: "get-timeline-gaps.jsx", fn: "ppb_getTimelineGaps" },
|
|
1046
|
+
"get-offline-media": { file: "get-offline-media.jsx", fn: "ppb_getOfflineMedia" },
|
|
1047
|
+
"get-used-media-report": { file: "get-used-media-report.jsx", fn: "ppb_getUsedMediaReport" },
|
|
1048
|
+
"get-all-project-paths": { file: "get-all-project-paths.jsx", fn: "ppb_getAllProjectPaths" },
|
|
1049
|
+
"get-unused-media": { file: "get-unused-media.jsx", fn: "ppb_getUnusedMedia" },
|
|
1050
|
+
"get-duplicate-media": { file: "get-duplicate-media.jsx", fn: "ppb_getDuplicateMedia" },
|
|
1051
|
+
"get-clip-links": { file: "get-clip-links.jsx", fn: "ppb_getClipLinks" },
|
|
1052
|
+
"get-insertion-bin": { file: "get-insertion-bin.jsx", fn: "ppb_getInsertionBin" },
|
|
1053
|
+
"get-project-panel-metadata": { file: "get-project-panel-metadata.jsx", fn: "ppb_getProjectPanelMetadata" },
|
|
1054
|
+
"list-available-effects": { file: "list-available-effects.jsx", fn: "ppb_listAvailableEffects" },
|
|
1055
|
+
"list-available-audio-effects": { file: "list-available-audio-effects.jsx", fn: "ppb_listAvailableAudioEffects" },
|
|
1056
|
+
"list-available-transitions": { file: "list-available-transitions.jsx", fn: "ppb_listAvailableTransitions" },
|
|
1057
|
+
"list-available-audio-transitions": { file: "list-available-audio-transitions.jsx", fn: "ppb_listAvailableAudioTransitions" },
|
|
1058
|
+
"list-markers": { file: "list-markers.jsx", fn: "ppb_listMarkers" },
|
|
1059
|
+
"get-clip-markers": { file: "get-clip-markers.jsx", fn: "ppb_getClipMarkers" },
|
|
1060
|
+
"get-sequence-markers-by-type": { file: "get-sequence-markers-by-type.jsx", fn: "ppb_getSequenceMarkersByType" },
|
|
1061
|
+
"get-item-metadata": { file: "get-item-metadata.jsx", fn: "ppb_getItemMetadata" },
|
|
1062
|
+
"get-color-label": { file: "get-color-label.jsx", fn: "ppb_getColorLabel" },
|
|
1063
|
+
"get-footage-interpretation": { file: "get-footage-interpretation.jsx", fn: "ppb_getFootageInterpretation" },
|
|
1064
|
+
"get-xmp-metadata": { file: "get-xmp-metadata.jsx", fn: "ppb_getXmpMetadata" },
|
|
1065
|
+
"get-color-space": { file: "get-color-space.jsx", fn: "ppb_getColorSpace" },
|
|
1066
|
+
"get-render-queue-status": { file: "get-render-queue-status.jsx", fn: "ppb_getRenderQueueStatus" },
|
|
1067
|
+
"get-clip-at-position": { file: "get-clip-at-position.jsx", fn: "ppb_getClipAtPosition" },
|
|
1068
|
+
"get-clip-at-playhead": { file: "get-clip-at-playhead.jsx", fn: "ppb_getClipAtPlayhead" },
|
|
1069
|
+
"get-next-edit-point": { file: "get-next-edit-point.jsx", fn: "ppb_getNextEditPoint" },
|
|
1070
|
+
"get-sequence-count": { file: "get-sequence-count.jsx", fn: "ppb_getSequenceCount" },
|
|
1071
|
+
"get-total-clip-count": { file: "get-total-clip-count.jsx", fn: "ppb_getTotalClipCount" },
|
|
1072
|
+
"get-target-tracks": { file: "get-target-tracks.jsx", fn: "ppb_getTargetTracks" },
|
|
1073
|
+
"get-track-info": { file: "get-track-info.jsx", fn: "ppb_getTrackInfo" },
|
|
1074
|
+
"get-encoder-presets": { file: "get-encoder-presets.jsx", fn: "ppb_getEncoderPresets" },
|
|
1075
|
+
"get-qe-clip-info": { file: "get-qe-clip-info.jsx", fn: "ppb_getQeClipInfo" },
|
|
1076
|
+
"get-source-monitor-info": { file: "get-source-monitor-info.jsx", fn: "ppb_getSourceMonitorInfo" },
|
|
1077
|
+
"get-clip-adjustment-layer": { file: "get-clip-adjustment-layer.jsx", fn: "ppb_getClipAdjustmentLayer" },
|
|
1078
|
+
"add-marker": { file: "add-marker.jsx", fn: "ppb_addMarker" },
|
|
1079
|
+
"update-marker": { file: "update-marker.jsx", fn: "ppb_updateMarker" },
|
|
1080
|
+
"delete-marker": { file: "delete-marker.jsx", fn: "ppb_deleteMarker" },
|
|
1081
|
+
"add-marker-to-project-item": { file: "add-marker-to-project-item.jsx", fn: "ppb_addMarkerToProjectItem" },
|
|
1082
|
+
"redo": { file: "redo.jsx", fn: "ppb_redo" },
|
|
1083
|
+
"undo": { file: "undo.jsx", fn: "ppb_undo" },
|
|
1084
|
+
"move-playhead-to-edit": { file: "move-playhead-to-edit.jsx", fn: "ppb_movePlayheadToEdit" },
|
|
1085
|
+
"set-poster-frame": { file: "set-poster-frame.jsx", fn: "ppb_setPosterFrame" },
|
|
1086
|
+
"select-project-item": { file: "select-project-item.jsx", fn: "ppb_selectProjectItem" },
|
|
1087
|
+
"select-clips-by-name": { file: "select-clips-by-name.jsx", fn: "ppb_selectClipsByName" },
|
|
1088
|
+
"select-all-clips": { file: "select-all-clips.jsx", fn: "ppb_selectAllClips" },
|
|
1089
|
+
"deselect-all-clips": { file: "deselect-all-clips.jsx", fn: "ppb_deselectAllClips" },
|
|
1090
|
+
"select-clips-in-range": { file: "select-clips-in-range.jsx", fn: "ppb_selectClipsInRange" },
|
|
1091
|
+
"select-clips-by-color": { file: "select-clips-by-color.jsx", fn: "ppb_selectClipsByColor" },
|
|
1092
|
+
"invert-selection": { file: "invert-selection.jsx", fn: "ppb_invertSelection" },
|
|
1093
|
+
"select-disabled-clips": { file: "select-disabled-clips.jsx", fn: "ppb_selectDisabledClips" },
|
|
1094
|
+
"set-clip-selection": { file: "set-clip-selection.jsx", fn: "ppb_setClipSelection" },
|
|
1095
|
+
"add-track": { file: "add-track.jsx", fn: "ppb_addTrack" },
|
|
1096
|
+
"lock-track": { file: "lock-track.jsx", fn: "ppb_lockTrack" },
|
|
1097
|
+
"set-track-visibility": { file: "set-track-visibility.jsx", fn: "ppb_setTrackVisibility" },
|
|
1098
|
+
"set-track-mute": { file: "set-track-mute.jsx", fn: "ppb_setTrackMute" },
|
|
1099
|
+
"rename-track": { file: "rename-track.jsx", fn: "ppb_renameTrack" },
|
|
1100
|
+
"set-target-track": { file: "set-target-track.jsx", fn: "ppb_setTargetTrack" },
|
|
1101
|
+
"set-all-tracks-targeted": { file: "set-all-tracks-targeted.jsx", fn: "ppb_setAllTracksTargeted" },
|
|
1102
|
+
"set-clip-position": { file: "set-clip-position.jsx", fn: "ppb_setClipPosition" },
|
|
1103
|
+
"set-clip-scale": { file: "set-clip-scale.jsx", fn: "ppb_setClipScale" },
|
|
1104
|
+
"set-clip-rotation": { file: "set-clip-rotation.jsx", fn: "ppb_setClipRotation" },
|
|
1105
|
+
"set-clip-anchor-point": { file: "set-clip-anchor-point.jsx", fn: "ppb_setClipAnchorPoint" },
|
|
1106
|
+
"set-clip-opacity": { file: "set-clip-opacity.jsx", fn: "ppb_setClipOpacity" },
|
|
1107
|
+
"set-uniform-scale": { file: "set-uniform-scale.jsx", fn: "ppb_setUniformScale" },
|
|
1108
|
+
"set-scale-width-height": { file: "set-scale-width-height.jsx", fn: "ppb_setScaleWidthHeight" },
|
|
1109
|
+
"set-anti-alias-quality": { file: "set-anti-alias-quality.jsx", fn: "ppb_setAntiAliasQuality" },
|
|
1110
|
+
"set-blend-mode": { file: "set-blend-mode.jsx", fn: "ppb_setBlendMode" },
|
|
1111
|
+
"apply-effect": { file: "apply-effect.jsx", fn: "ppb_applyEffect" },
|
|
1112
|
+
"apply-audio-effect": { file: "apply-audio-effect.jsx", fn: "ppb_applyAudioEffect" },
|
|
1113
|
+
"remove-effect": { file: "remove-effect.jsx", fn: "ppb_removeEffect" },
|
|
1114
|
+
"remove-effect-by-name": { file: "remove-effect-by-name.jsx", fn: "ppb_removeEffectByName" },
|
|
1115
|
+
"remove-all-effects": { file: "remove-all-effects.jsx", fn: "ppb_removeAllEffects" },
|
|
1116
|
+
"color-correct": { file: "color-correct.jsx", fn: "ppb_colorCorrect" },
|
|
1117
|
+
"apply-lut": { file: "apply-lut.jsx", fn: "ppb_applyLut" },
|
|
1118
|
+
"stabilize-clip": { file: "stabilize-clip.jsx", fn: "ppb_stabilizeClip" },
|
|
1119
|
+
"copy-effects-between-clips": { file: "copy-effects-between-clips.jsx", fn: "ppb_copyEffectsBetweenClips" },
|
|
1120
|
+
"copy-effect-values": { file: "copy-effect-values.jsx", fn: "ppb_copyEffectValues" },
|
|
1121
|
+
"batch-apply-effect": { file: "batch-apply-effect.jsx", fn: "ppb_batchApplyEffect" },
|
|
1122
|
+
"add-to-timeline": { file: "add-to-timeline.jsx", fn: "ppb_addToTimeline" },
|
|
1123
|
+
"remove-from-timeline": { file: "remove-from-timeline.jsx", fn: "ppb_removeFromTimeline" },
|
|
1124
|
+
"move-clip": { file: "move-clip.jsx", fn: "ppb_moveClip" },
|
|
1125
|
+
"trim-clip": { file: "trim-clip.jsx", fn: "ppb_trimClip" },
|
|
1126
|
+
"split-clip": { file: "split-clip.jsx", fn: "ppb_splitClip" },
|
|
1127
|
+
"duplicate-clip": { file: "duplicate-clip.jsx", fn: "ppb_duplicateClip" },
|
|
1128
|
+
"replace-clip": { file: "replace-clip.jsx", fn: "ppb_replaceClip" },
|
|
1129
|
+
"set-clip-speed": { file: "set-clip-speed.jsx", fn: "ppb_setClipSpeed" },
|
|
1130
|
+
"get-clip-speed": { file: "get-clip-speed.jsx", fn: "ppb_getClipSpeed" },
|
|
1131
|
+
"import-media": { file: "import-media.jsx", fn: "ppb_importMedia" },
|
|
1132
|
+
"import-folder": { file: "import-folder.jsx", fn: "ppb_importFolder" },
|
|
1133
|
+
"import-image-sequence": { file: "import-image-sequence.jsx", fn: "ppb_importImageSequence" },
|
|
1134
|
+
"create-bin": { file: "create-bin.jsx", fn: "ppb_createBin" },
|
|
1135
|
+
"rename-bin": { file: "rename-bin.jsx", fn: "ppb_renameBin" },
|
|
1136
|
+
"move-items-to-bin": { file: "move-items-to-bin.jsx", fn: "ppb_moveItemsToBin" },
|
|
1137
|
+
"relink-media": { file: "relink-media.jsx", fn: "ppb_relinkMedia" },
|
|
1138
|
+
"refresh-media": { file: "refresh-media.jsx", fn: "ppb_refreshMedia" },
|
|
1139
|
+
"set-item-offline": { file: "set-item-offline.jsx", fn: "ppb_setItemOffline" },
|
|
1140
|
+
"detach-proxy": { file: "detach-proxy.jsx", fn: "ppb_detachProxy" },
|
|
1141
|
+
"set-override-frame-rate": { file: "set-override-frame-rate.jsx", fn: "ppb_setOverrideFrameRate" },
|
|
1142
|
+
"set-override-pixel-aspect-ratio": { file: "set-override-pixel-aspect-ratio.jsx", fn: "ppb_setOverridePixelAspectRatio" },
|
|
1143
|
+
"set-scale-to-frame-size": { file: "set-scale-to-frame-size.jsx", fn: "ppb_setScaleToFrameSize" },
|
|
1144
|
+
"set-item-start-time": { file: "set-item-start-time.jsx", fn: "ppb_setItemStartTime" },
|
|
1145
|
+
"rename-project-item": { file: "rename-project-item.jsx", fn: "ppb_renameProjectItem" }
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
// Files already evalFile'd this panel session. Deliberately keyed on this
|
|
1149
|
+
// object — which resets every time index.jsx re-evaluates (i.e. on every
|
|
1150
|
+
// panel load/reload) — and NOT on `typeof ppb_xxx === "function"`: if the
|
|
1151
|
+
// ExtendScript engine outlives a panel reload, a stale function from the
|
|
1152
|
+
// previous session would otherwise mask a newer command file on disk and
|
|
1153
|
+
// break the edit-file → reload-panel dev loop.
|
|
1154
|
+
var PPB_LOADED = {};
|
|
1155
|
+
|
|
1156
|
+
// Single entry point called by the panel (main.js) for every command:
|
|
1157
|
+
// ppb_dispatch('<command-name>', '<argsJson>')
|
|
1158
|
+
// Loads host/commands/<file> on first use, then calls the command function
|
|
1159
|
+
// with argsJson. The plugin's root directory comes from args.pluginDir,
|
|
1160
|
+
// which main.js injects into every command's args ($.fileName doesn't
|
|
1161
|
+
// resolve reliably for a manifest-loaded .jsx, so the panel supplies it).
|
|
1162
|
+
function ppb_dispatch(commandName, argsJson) {
|
|
1163
|
+
try {
|
|
1164
|
+
var entry = PPB_COMMANDS[commandName];
|
|
1165
|
+
if (!entry) {
|
|
1166
|
+
return JSON.stringify({ ok: false, error: "unknown command: " + commandName });
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
if (!PPB_LOADED[entry.file]) {
|
|
1170
|
+
var pluginDir = null;
|
|
1171
|
+
try {
|
|
1172
|
+
pluginDir = JSON.parse(argsJson).pluginDir;
|
|
1173
|
+
} catch (e) {
|
|
1174
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
1175
|
+
}
|
|
1176
|
+
if (!pluginDir || typeof pluginDir !== "string") {
|
|
1177
|
+
return JSON.stringify({ ok: false, error: "pluginDir was not provided by the panel" });
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
var commandFile = new File(pluginDir + "/host/commands/" + entry.file);
|
|
1181
|
+
if (!commandFile.exists) {
|
|
1182
|
+
return JSON.stringify({ ok: false, error: "command file not found: " + commandFile.fsName });
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// Drop any stale copy from a previous panel session first, so the
|
|
1186
|
+
// eval() lookup below can only resolve the freshly-loaded function
|
|
1187
|
+
// (never a leftover global masking a broken/edited file on disk).
|
|
1188
|
+
try {
|
|
1189
|
+
delete $.global[entry.fn];
|
|
1190
|
+
} catch (e) {
|
|
1191
|
+
// best-effort
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
try {
|
|
1195
|
+
$.evalFile(commandFile.fsName);
|
|
1196
|
+
} catch (e) {
|
|
1197
|
+
return JSON.stringify({ ok: false, error: "failed to load " + entry.file + ": " + e.toString() });
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
// $.evalFile evaluates the file in the CALLING scope (confirmed
|
|
1201
|
+
// live 2026-07-17): its function declarations land in this
|
|
1202
|
+
// function's local scope, NOT on $.global. Resolve the command's
|
|
1203
|
+
// entry point from the local scope and publish it globally — the
|
|
1204
|
+
// closure keeps the file's sibling helper functions reachable from
|
|
1205
|
+
// it, and each file's helpers stay isolated in their own load
|
|
1206
|
+
// scope. Do NOT trust a pre-existing $.global[entry.fn] here: if
|
|
1207
|
+
// the ExtendScript engine outlives a panel reload, that global is
|
|
1208
|
+
// a stale copy from an earlier session masking the file on disk.
|
|
1209
|
+
var loadedFn = null;
|
|
1210
|
+
try {
|
|
1211
|
+
loadedFn = eval(entry.fn);
|
|
1212
|
+
} catch (e) {
|
|
1213
|
+
loadedFn = null;
|
|
1214
|
+
}
|
|
1215
|
+
if (typeof loadedFn !== "function") {
|
|
1216
|
+
return JSON.stringify({ ok: false, error: entry.file + " loaded but did not define " + entry.fn + "()" });
|
|
1217
|
+
}
|
|
1218
|
+
$.global[entry.fn] = loadedFn;
|
|
1219
|
+
|
|
1220
|
+
PPB_LOADED[entry.file] = true;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
return $.global[entry.fn](argsJson);
|
|
1224
|
+
} catch (e) {
|
|
1225
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
1226
|
+
}
|
|
1227
|
+
}
|