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,160 @@
|
|
|
1
|
+
// Command: set-clip-speed → ppb_setClipSpeed
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// resolveTimelineClip, resolveQeClip, ensureQEEnabled,
|
|
5
|
+
// activateSequenceForQE, TICKS_PER_SECOND, ...) are already defined
|
|
6
|
+
// there.
|
|
7
|
+
//
|
|
8
|
+
// Sets a clip's playback speed via QE. LIVE-CALIBRATED 2026-07-17 (see
|
|
9
|
+
// BUILD_FINDINGS.md corrections): the working signature on this build is
|
|
10
|
+
// the 5-arg
|
|
11
|
+
// qeClip.setSpeed(speedMultiplier, ticksString, reverse, false, false)
|
|
12
|
+
// where:
|
|
13
|
+
// - arg1 is a MULTIPLIER (1 = 100%), NOT a percent — and the
|
|
14
|
+
// standard-DOM clip.getSpeed() read-back uses the same scale (a
|
|
15
|
+
// normal clip reads 1, not 100);
|
|
16
|
+
// - arg2 must be a plausible ticks string — garbage there (e.g. the
|
|
17
|
+
// literal "ticks") collapses the clip to ONE FRAME. The clip's own
|
|
18
|
+
// current duration in ticks is passed;
|
|
19
|
+
// - arg3 is the reverse flag (verified via isSpeedReversed()) —
|
|
20
|
+
// negative multipliers do NOT reverse, they clamp to a degenerate
|
|
21
|
+
// state, so reversal must go through this flag;
|
|
22
|
+
// - args 4/5 are unidentified; false/false is the tested-safe value.
|
|
23
|
+
// Speed-up shortens the timeline item to source/speed ROUNDED UP to
|
|
24
|
+
// whole frames (getSpeed() then reads the post-rounding actual — e.g.
|
|
25
|
+
// requesting 50x on a 27.16s clip yields 48.5). Slow-down does NOT
|
|
26
|
+
// extend the item; source usage truncates instead.
|
|
27
|
+
//
|
|
28
|
+
// MUTATION RULE: verified via the STANDARD-DOM clip.getSpeed()/
|
|
29
|
+
// isSpeedReversed() read-back after the QE call — never trusting
|
|
30
|
+
// setSpeed()'s own return value. Because of frame rounding the speed
|
|
31
|
+
// comparison uses a 5% relative tolerance.
|
|
32
|
+
|
|
33
|
+
function ppb_setClipSpeed(argsJson) {
|
|
34
|
+
try {
|
|
35
|
+
var args;
|
|
36
|
+
try {
|
|
37
|
+
args = JSON.parse(argsJson);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
43
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
44
|
+
}
|
|
45
|
+
if (typeof args.trackIndex !== "number" || typeof args.clipIndex !== "number") {
|
|
46
|
+
return JSON.stringify({ ok: false, error: "trackIndex and clipIndex are required" });
|
|
47
|
+
}
|
|
48
|
+
if (typeof args.speedPercent !== "number" || args.speedPercent === 0) {
|
|
49
|
+
return JSON.stringify({ ok: false, error: "speedPercent is required and must be non-zero (100 = normal, negative = reversed)" });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var reverse = args.speedPercent < 0;
|
|
53
|
+
var multiplier = Math.abs(args.speedPercent) / 100;
|
|
54
|
+
|
|
55
|
+
if (!app.project) {
|
|
56
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var seq = null;
|
|
60
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
61
|
+
seq = findSequenceByName(args.sequenceName);
|
|
62
|
+
if (!seq) {
|
|
63
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
seq = app.project.activeSequence;
|
|
67
|
+
if (!seq) {
|
|
68
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
var stdResolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
|
|
73
|
+
if (stdResolved.error) {
|
|
74
|
+
return JSON.stringify({ ok: false, error: stdResolved.error });
|
|
75
|
+
}
|
|
76
|
+
var stdClip = stdResolved.clip;
|
|
77
|
+
|
|
78
|
+
var previousSpeed = null;
|
|
79
|
+
var previousReversed = null;
|
|
80
|
+
try { previousSpeed = stdClip.getSpeed(); } catch (e2) { previousSpeed = null; }
|
|
81
|
+
try { previousReversed = stdClip.isSpeedReversed() === true || stdClip.isSpeedReversed() === 1; } catch (e3) { previousReversed = null; }
|
|
82
|
+
|
|
83
|
+
// arg2 of setSpeed must be a plausible ticks string — the clip's own
|
|
84
|
+
// current timeline duration.
|
|
85
|
+
var durTicks = null;
|
|
86
|
+
try {
|
|
87
|
+
durTicks = String(Math.round((stdClip.end.seconds - stdClip.start.seconds) * TICKS_PER_SECOND));
|
|
88
|
+
} catch (e4) {
|
|
89
|
+
return JSON.stringify({ ok: false, error: "could not read the clip's duration for setSpeed's ticks argument: " + e4.toString() });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
ensureQEEnabled();
|
|
94
|
+
activateSequenceForQE(seq);
|
|
95
|
+
} catch (e5) {
|
|
96
|
+
return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e5.toString() });
|
|
97
|
+
}
|
|
98
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
99
|
+
return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var qeSeq;
|
|
103
|
+
try {
|
|
104
|
+
qeSeq = qe.project.getActiveSequence();
|
|
105
|
+
} catch (e6) {
|
|
106
|
+
return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e6.toString() });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var qeResolved = resolveQeClip(qeSeq, args.trackType, args.trackIndex, args.clipIndex);
|
|
110
|
+
if (qeResolved.error) {
|
|
111
|
+
return JSON.stringify({ ok: false, error: qeResolved.error });
|
|
112
|
+
}
|
|
113
|
+
var qeClip = qeResolved.qeClip;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
qeClip.setSpeed(multiplier, durTicks, reverse, false, false);
|
|
117
|
+
} catch (e7) {
|
|
118
|
+
return JSON.stringify({
|
|
119
|
+
ok: false,
|
|
120
|
+
error: "qeClip.setSpeed(multiplier, ticksString, reverse, false, false) threw: " + e7.toString(),
|
|
121
|
+
previousSpeed: previousSpeed,
|
|
122
|
+
previousReversed: previousReversed
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
var newSpeed = null;
|
|
127
|
+
var newReversed = null;
|
|
128
|
+
try { newSpeed = stdClip.getSpeed(); } catch (e8) { newSpeed = null; }
|
|
129
|
+
try { newReversed = stdClip.isSpeedReversed() === true || stdClip.isSpeedReversed() === 1; } catch (e9) { newReversed = null; }
|
|
130
|
+
|
|
131
|
+
// Frame rounding shifts the actual applied speed (see header) — 5%
|
|
132
|
+
// relative tolerance on the multiplier, exact match on the flag.
|
|
133
|
+
var speedVerified = newSpeed !== null && multiplier > 0 &&
|
|
134
|
+
Math.abs(newSpeed - multiplier) / multiplier <= 0.05;
|
|
135
|
+
var reverseVerified = newReversed !== null ? (newReversed === reverse) : null;
|
|
136
|
+
|
|
137
|
+
return JSON.stringify({
|
|
138
|
+
ok: true,
|
|
139
|
+
result: {
|
|
140
|
+
sequenceName: seq.name,
|
|
141
|
+
trackType: args.trackType,
|
|
142
|
+
trackIndex: args.trackIndex,
|
|
143
|
+
clipIndex: args.clipIndex,
|
|
144
|
+
clipName: (function () { try { return stdClip.name; } catch (e) { return null; } })(),
|
|
145
|
+
requestedSpeedPercent: args.speedPercent,
|
|
146
|
+
requestedMultiplier: multiplier,
|
|
147
|
+
reverse: reverse,
|
|
148
|
+
previousSpeed: previousSpeed,
|
|
149
|
+
previousReversed: previousReversed,
|
|
150
|
+
newSpeed: newSpeed,
|
|
151
|
+
newSpeedPercent: newSpeed !== null ? newSpeed * 100 : null,
|
|
152
|
+
newReversed: newReversed,
|
|
153
|
+
verified: speedVerified && reverseVerified !== false,
|
|
154
|
+
note: "getSpeed() values are MULTIPLIERS on this build (1 = 100%); the applied speed is frame-rounded, so newSpeed can differ slightly from the request. Slow-motion does not extend the timeline item."
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
} catch (e) {
|
|
158
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Command: set-clip-volume → ppb_setClipVolume
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// findVolumeLevelProperty, dbToLinearCalibrated, linearToDbCalibrated, ...)
|
|
5
|
+
// are already defined there.
|
|
6
|
+
//
|
|
7
|
+
// Standard-DOM mutation. Ported from leancoderkavy's premiere-pro-mcp
|
|
8
|
+
// `set_clip_volume` tool (track-targeting.ts), which sets the Volume
|
|
9
|
+
// component's Level property directly to the raw dB number passed in —
|
|
10
|
+
// but PREMIERE_API_NOTES.md is explicit that Level is LINEAR AMPLITUDE, not
|
|
11
|
+
// dB, so setValue(dB) as the reference does is almost certainly wrong on
|
|
12
|
+
// any real build. This command instead converts the requested dB to
|
|
13
|
+
// linear amplitude via hetpatel's empirical calibration for this build
|
|
14
|
+
// family (linear = 10^((dB-15)/20)) before calling setValue().
|
|
15
|
+
//
|
|
16
|
+
// *** CALIBRATION UNCERTAINTY — READ BEFORE TRUSTING THIS COMMAND ***
|
|
17
|
+
// The three reference MCP repos studied for this port do NOT agree on the
|
|
18
|
+
// dB->linear formula: hetpatel's calibrated 10^((dB-15)/20) (used here),
|
|
19
|
+
// leancoderkavy's uncalibrated 10^(dB/20), and ayushozha's "mostly raw dB,
|
|
20
|
+
// docs admit it's linear". None of this has been live-verified against
|
|
21
|
+
// THIS Premiere build — do that before relying on the resulting level
|
|
22
|
+
// sounding correct. Both the raw linear values (previous/requested/new)
|
|
23
|
+
// AND the requested dB are returned so a caller can sanity-check/recalibrate
|
|
24
|
+
// without re-running the mutation.
|
|
25
|
+
function ppb_setClipVolume(argsJson) {
|
|
26
|
+
try {
|
|
27
|
+
var args;
|
|
28
|
+
try {
|
|
29
|
+
args = JSON.parse(argsJson);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
35
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
36
|
+
}
|
|
37
|
+
if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
|
|
38
|
+
return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
|
|
39
|
+
}
|
|
40
|
+
if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
|
|
41
|
+
return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
|
|
42
|
+
}
|
|
43
|
+
if (typeof args.db !== "number" || isNaN(args.db)) {
|
|
44
|
+
return JSON.stringify({ ok: false, error: "db must be a number" });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!app.project) {
|
|
48
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var seq = null;
|
|
52
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
53
|
+
seq = findSequenceByName(args.sequenceName);
|
|
54
|
+
if (!seq) {
|
|
55
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
seq = app.project.activeSequence;
|
|
59
|
+
if (!seq) {
|
|
60
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
65
|
+
var numTracks = trackCollection.numTracks;
|
|
66
|
+
if (args.trackIndex >= numTracks) {
|
|
67
|
+
return JSON.stringify({
|
|
68
|
+
ok: false,
|
|
69
|
+
error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var track = trackCollection[args.trackIndex];
|
|
74
|
+
var numClips = track.clips.numItems;
|
|
75
|
+
if (args.clipIndex >= numClips) {
|
|
76
|
+
return JSON.stringify({
|
|
77
|
+
ok: false,
|
|
78
|
+
error: "clipIndex " + args.clipIndex + " is out of range — track " + args.trackIndex + " has " + numClips + " clip(s)"
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var clip = track.clips[args.clipIndex];
|
|
83
|
+
var clipName = null;
|
|
84
|
+
try { clipName = clip.name; } catch (e) { clipName = null; }
|
|
85
|
+
|
|
86
|
+
var levelProp = findVolumeLevelProperty(clip);
|
|
87
|
+
if (!levelProp) {
|
|
88
|
+
return JSON.stringify({ ok: false, error: "could not find Volume/Level property on clip — is this an audio clip?" });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var previousLinear = null;
|
|
92
|
+
try { previousLinear = levelProp.getValue(); } catch (e) { previousLinear = null; }
|
|
93
|
+
|
|
94
|
+
var requestedLinear = dbToLinearCalibrated(args.db);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
levelProp.setValue(requestedLinear, true);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
return JSON.stringify({ ok: false, error: "levelProp.setValue() failed: " + e.toString() });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
var newLinear = null;
|
|
103
|
+
try { newLinear = levelProp.getValue(); } catch (e) { newLinear = null; }
|
|
104
|
+
|
|
105
|
+
var verified = newLinear !== null && Math.abs(newLinear - requestedLinear) < 0.0005;
|
|
106
|
+
|
|
107
|
+
var result = {
|
|
108
|
+
sequenceName: seq.name,
|
|
109
|
+
trackType: args.trackType,
|
|
110
|
+
trackIndex: args.trackIndex,
|
|
111
|
+
clipIndex: args.clipIndex,
|
|
112
|
+
clipName: clipName,
|
|
113
|
+
requestedDb: args.db,
|
|
114
|
+
previousValue: previousLinear,
|
|
115
|
+
requestedValue: requestedLinear,
|
|
116
|
+
newValue: newLinear,
|
|
117
|
+
verified: verified,
|
|
118
|
+
previousDbEstimate: linearToDbCalibrated(previousLinear),
|
|
119
|
+
calibrationNote: "Level is LINEAR AMPLITUDE, not dB. Converted via hetpatel's empirical " +
|
|
120
|
+
"calibration linear = 10^((db-15)/20) — UNVERIFIED against this Premiere build; " +
|
|
121
|
+
"other reference repos use different formulas (see file header comment)."
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return JSON.stringify({ ok: true, result: result });
|
|
125
|
+
} catch (e) {
|
|
126
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Command: set-color-label → ppb_setColorLabel
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context.
|
|
4
|
+
//
|
|
5
|
+
// Project-item addressing: at least one of nodeId/name is required (see
|
|
6
|
+
// get-item-metadata.jsx for the shared design note — the resolver is
|
|
7
|
+
// duplicated per-file since command files load independently).
|
|
8
|
+
//
|
|
9
|
+
// WRITE command — write-side counterpart of get-color-label. Undo is
|
|
10
|
+
// NON-FUNCTIONAL on this build — `previousValue` is the only restoration
|
|
11
|
+
// path. get-color-label degrades honestly when getColorLabel is absent
|
|
12
|
+
// on a build; this command mirrors that for both the getter (used for
|
|
13
|
+
// previousValue/newValue) and the setter itself.
|
|
14
|
+
|
|
15
|
+
function ppbFindItemSetColorLabel_walk(item, args, depth) {
|
|
16
|
+
if (depth > 32) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var isBin = false;
|
|
21
|
+
try {
|
|
22
|
+
isBin = typeof ProjectItemType !== "undefined" && item.type === ProjectItemType.BIN;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
isBin = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var matched = false;
|
|
28
|
+
if (args.nodeId !== null) {
|
|
29
|
+
try { matched = item.nodeId === args.nodeId; } catch (e) { matched = false; }
|
|
30
|
+
} else if (args.name !== null) {
|
|
31
|
+
try { matched = item.name === args.name; } catch (e) { matched = false; }
|
|
32
|
+
}
|
|
33
|
+
if (matched) {
|
|
34
|
+
return item;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (isBin && item.children) {
|
|
38
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
39
|
+
var found = ppbFindItemSetColorLabel_walk(item.children[i], args, depth + 1);
|
|
40
|
+
if (found) {
|
|
41
|
+
return found;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function ppbFindItemSetColorLabel_resolve(args) {
|
|
49
|
+
var root = app.project.rootItem;
|
|
50
|
+
for (var i = 0; i < root.children.numItems; i++) {
|
|
51
|
+
var found = ppbFindItemSetColorLabel_walk(root.children[i], args, 1);
|
|
52
|
+
if (found) {
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ppb_setColorLabel(argsJson) {
|
|
60
|
+
try {
|
|
61
|
+
var args;
|
|
62
|
+
try {
|
|
63
|
+
args = JSON.parse(argsJson);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var hasNodeId = typeof args.nodeId === "string" && args.nodeId.length > 0;
|
|
69
|
+
var hasName = typeof args.name === "string" && args.name.length > 0;
|
|
70
|
+
if (!hasNodeId && !hasName) {
|
|
71
|
+
return JSON.stringify({ ok: false, error: "either nodeId or name is required" });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof args.colorLabel !== "number" || args.colorLabel < 0 || args.colorLabel > 15) {
|
|
75
|
+
return JSON.stringify({ ok: false, error: "colorLabel (integer 0-15) is required" });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!app.project) {
|
|
79
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var item = ppbFindItemSetColorLabel_resolve({
|
|
83
|
+
nodeId: hasNodeId ? args.nodeId : null,
|
|
84
|
+
name: hasNodeId ? null : args.name
|
|
85
|
+
});
|
|
86
|
+
if (!item) {
|
|
87
|
+
return JSON.stringify({ ok: false, error: "no project item found matching the given nodeId/name" });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof item.setColorLabel !== "function") {
|
|
91
|
+
return JSON.stringify({ ok: false, error: "setColorLabel is not available on this Premiere build" });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var previousValue = null;
|
|
95
|
+
try { previousValue = item.getColorLabel(); } catch (e) { previousValue = null; }
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
item.setColorLabel(args.colorLabel);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return JSON.stringify({ ok: false, error: "setColorLabel() failed: " + e.toString() });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
var newValue = null;
|
|
104
|
+
try { newValue = item.getColorLabel(); } catch (e) { newValue = null; }
|
|
105
|
+
|
|
106
|
+
var verified = newValue !== null && newValue === args.colorLabel;
|
|
107
|
+
|
|
108
|
+
var result = {
|
|
109
|
+
name: null,
|
|
110
|
+
nodeId: null,
|
|
111
|
+
previousValue: previousValue,
|
|
112
|
+
requestedValue: args.colorLabel,
|
|
113
|
+
newValue: newValue,
|
|
114
|
+
verified: verified
|
|
115
|
+
};
|
|
116
|
+
try { result.name = item.name; } catch (e) { result.name = null; }
|
|
117
|
+
try { result.nodeId = item.nodeId; } catch (e) { result.nodeId = null; }
|
|
118
|
+
|
|
119
|
+
return JSON.stringify({ ok: true, result: result });
|
|
120
|
+
} catch (e) {
|
|
121
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Command: set-color-value → ppb_setColorValue
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// findClipComponent, findComponentProperty, valuesApproximatelyEqual, ...)
|
|
5
|
+
// are already defined there.
|
|
6
|
+
//
|
|
7
|
+
// Standard-DOM mutation. Ported from leancoderkavy's premiere-pro-mcp
|
|
8
|
+
// `set_color_value` tool (advanced.ts), addressed here by
|
|
9
|
+
// trackType/trackIndex/clipIndex + componentName/propertyName (same
|
|
10
|
+
// convention as get-effect-properties/set-effect-property) instead of
|
|
11
|
+
// node_id. Sets a color-typed property (e.g. a Lumetri tint, a title fill
|
|
12
|
+
// color) via prop.setColorValue(alpha, red, green, blue, true) — each
|
|
13
|
+
// channel 0-255, per PREMIERE_API_NOTES.md's Property API block. Mutating
|
|
14
|
+
// — undo is non-functional on this build, so previousValue is the
|
|
15
|
+
// caller's only restoration path.
|
|
16
|
+
function ppb_setColorValue(argsJson) {
|
|
17
|
+
try {
|
|
18
|
+
var args;
|
|
19
|
+
try {
|
|
20
|
+
args = JSON.parse(argsJson);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
26
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
27
|
+
}
|
|
28
|
+
if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
|
|
29
|
+
return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
|
|
30
|
+
}
|
|
31
|
+
if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
|
|
32
|
+
return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
|
|
33
|
+
}
|
|
34
|
+
if (typeof args.componentName !== "string" || !args.componentName) {
|
|
35
|
+
return JSON.stringify({ ok: false, error: "componentName is required" });
|
|
36
|
+
}
|
|
37
|
+
if (typeof args.propertyName !== "string" || !args.propertyName) {
|
|
38
|
+
return JSON.stringify({ ok: false, error: "propertyName is required" });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var channels = ["alpha", "red", "green", "blue"];
|
|
42
|
+
for (var c = 0; c < channels.length; c++) {
|
|
43
|
+
var v = args[channels[c]];
|
|
44
|
+
if (typeof v !== "number" || v < 0 || v > 255) {
|
|
45
|
+
return JSON.stringify({ ok: false, error: channels[c] + " must be a number between 0 and 255" });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!app.project) {
|
|
50
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var seq = null;
|
|
54
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
55
|
+
seq = findSequenceByName(args.sequenceName);
|
|
56
|
+
if (!seq) {
|
|
57
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
seq = app.project.activeSequence;
|
|
61
|
+
if (!seq) {
|
|
62
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
67
|
+
var numTracks = trackCollection.numTracks;
|
|
68
|
+
if (args.trackIndex >= numTracks) {
|
|
69
|
+
return JSON.stringify({
|
|
70
|
+
ok: false,
|
|
71
|
+
error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
var track = trackCollection[args.trackIndex];
|
|
76
|
+
var numClips = track.clips.numItems;
|
|
77
|
+
if (args.clipIndex >= numClips) {
|
|
78
|
+
return JSON.stringify({
|
|
79
|
+
ok: false,
|
|
80
|
+
error: "clipIndex " + args.clipIndex + " is out of range — track " + args.trackIndex + " has " + numClips + " clip(s)"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var clip = track.clips[args.clipIndex];
|
|
85
|
+
var clipName = null;
|
|
86
|
+
try { clipName = clip.name; } catch (e) { clipName = null; }
|
|
87
|
+
|
|
88
|
+
var comp = findClipComponent(clip, [args.componentName], [args.componentName]);
|
|
89
|
+
if (!comp) {
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
ok: false,
|
|
92
|
+
error: "component \"" + args.componentName + "\" not found on clip (matched against matchName and displayName)"
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
var compDisplayName = null;
|
|
96
|
+
try { compDisplayName = comp.displayName; } catch (e) { compDisplayName = null; }
|
|
97
|
+
|
|
98
|
+
var prop = findComponentProperty(comp, [args.propertyName]);
|
|
99
|
+
if (!prop) {
|
|
100
|
+
return JSON.stringify({
|
|
101
|
+
ok: false,
|
|
102
|
+
error: "property \"" + args.propertyName + "\" not found on component \"" + compDisplayName + "\""
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var previousValue = null;
|
|
107
|
+
try { previousValue = prop.getValue(); } catch (e) { previousValue = null; }
|
|
108
|
+
|
|
109
|
+
var alpha = args.alpha, red = args.red, green = args.green, blue = args.blue;
|
|
110
|
+
var setError = null;
|
|
111
|
+
try {
|
|
112
|
+
prop.setColorValue(alpha, red, green, blue, true);
|
|
113
|
+
} catch (e2) {
|
|
114
|
+
setError = e2.toString();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
var newValue = null;
|
|
118
|
+
try { newValue = prop.getValue(); } catch (e3) { newValue = null; }
|
|
119
|
+
|
|
120
|
+
var verified = false;
|
|
121
|
+
if (setError === null) {
|
|
122
|
+
if (newValue instanceof Array && newValue.length === 4) {
|
|
123
|
+
verified = valuesApproximatelyEqual(newValue, [alpha, red, green, blue], 1);
|
|
124
|
+
} else {
|
|
125
|
+
// No confirmed cross-build representation for a color value read
|
|
126
|
+
// back via getValue() (packed int vs. [a,r,g,b] array vs. other) —
|
|
127
|
+
// report the call succeeded without throwing, but don't claim a
|
|
128
|
+
// verified numeric match unless it's the expected 4-element array.
|
|
129
|
+
verified = false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return JSON.stringify({
|
|
134
|
+
ok: true,
|
|
135
|
+
result: {
|
|
136
|
+
sequenceName: seq.name,
|
|
137
|
+
trackType: args.trackType,
|
|
138
|
+
trackIndex: args.trackIndex,
|
|
139
|
+
clipIndex: args.clipIndex,
|
|
140
|
+
clipName: clipName,
|
|
141
|
+
componentName: compDisplayName,
|
|
142
|
+
propertyName: args.propertyName,
|
|
143
|
+
requestedColor: { alpha: alpha, red: red, green: green, blue: blue },
|
|
144
|
+
previousValue: previousValue,
|
|
145
|
+
newValue: newValue,
|
|
146
|
+
setError: setError,
|
|
147
|
+
verified: verified,
|
|
148
|
+
note: "verified only asserts a match when newValue round-trips as a 4-element [a,r,g,b] array — " +
|
|
149
|
+
"this property's getValue() representation is unconfirmed on this build."
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
} catch (e) {
|
|
153
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// Command: set-effect-property → ppb_setEffectProperty
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// findClipComponent, findComponentProperty, setComponentProperty, ...) are
|
|
5
|
+
// already defined there.
|
|
6
|
+
//
|
|
7
|
+
// Standard-DOM only — no QE needed. Ported from leancoderkavy's
|
|
8
|
+
// premiere-pro-mcp `set_effect_property` tool (keyframes.ts), addressed
|
|
9
|
+
// here by trackType/trackIndex/clipIndex + componentName/propertyName
|
|
10
|
+
// (same convention as get-effect-properties) instead of node_id. Unlike
|
|
11
|
+
// the reference tool (numbers only), this accepts number/string/boolean
|
|
12
|
+
// via an explicit valueType field for unambiguous typing over the wire —
|
|
13
|
+
// premiere_cli.py coerces --value to the right JSON type before sending
|
|
14
|
+
// based on --value-type. Mutating — undo is non-functional on this build,
|
|
15
|
+
// so previousValue is the caller's only restoration path.
|
|
16
|
+
function ppb_setEffectProperty(argsJson) {
|
|
17
|
+
try {
|
|
18
|
+
var args;
|
|
19
|
+
try {
|
|
20
|
+
args = JSON.parse(argsJson);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
26
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
27
|
+
}
|
|
28
|
+
if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
|
|
29
|
+
return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
|
|
30
|
+
}
|
|
31
|
+
if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
|
|
32
|
+
return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
|
|
33
|
+
}
|
|
34
|
+
if (typeof args.componentName !== "string" || !args.componentName) {
|
|
35
|
+
return JSON.stringify({ ok: false, error: "componentName is required" });
|
|
36
|
+
}
|
|
37
|
+
if (typeof args.propertyName !== "string" || !args.propertyName) {
|
|
38
|
+
return JSON.stringify({ ok: false, error: "propertyName is required" });
|
|
39
|
+
}
|
|
40
|
+
if (args.valueType !== "number" && args.valueType !== "string" && args.valueType !== "boolean") {
|
|
41
|
+
return JSON.stringify({ ok: false, error: "valueType must be \"number\", \"string\", or \"boolean\"" });
|
|
42
|
+
}
|
|
43
|
+
if (typeof args.value === "undefined") {
|
|
44
|
+
return JSON.stringify({ ok: false, error: "value is required" });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!app.project) {
|
|
48
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var seq = null;
|
|
52
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
53
|
+
seq = findSequenceByName(args.sequenceName);
|
|
54
|
+
if (!seq) {
|
|
55
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
seq = app.project.activeSequence;
|
|
59
|
+
if (!seq) {
|
|
60
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
65
|
+
var numTracks = trackCollection.numTracks;
|
|
66
|
+
if (args.trackIndex >= numTracks) {
|
|
67
|
+
return JSON.stringify({
|
|
68
|
+
ok: false,
|
|
69
|
+
error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var track = trackCollection[args.trackIndex];
|
|
74
|
+
var numClips = track.clips.numItems;
|
|
75
|
+
if (args.clipIndex >= numClips) {
|
|
76
|
+
return JSON.stringify({
|
|
77
|
+
ok: false,
|
|
78
|
+
error: "clipIndex " + args.clipIndex + " is out of range — track " + args.trackIndex + " has " + numClips + " clip(s)"
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var clip = track.clips[args.clipIndex];
|
|
83
|
+
var clipName = null;
|
|
84
|
+
try { clipName = clip.name; } catch (e) { clipName = null; }
|
|
85
|
+
|
|
86
|
+
var comp = findClipComponent(clip, [args.componentName], [args.componentName]);
|
|
87
|
+
if (!comp) {
|
|
88
|
+
return JSON.stringify({
|
|
89
|
+
ok: false,
|
|
90
|
+
error: "component \"" + args.componentName + "\" not found on clip (matched against matchName and displayName)"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
var compDisplayName = null;
|
|
94
|
+
try { compDisplayName = comp.displayName; } catch (e) { compDisplayName = null; }
|
|
95
|
+
|
|
96
|
+
var setResult = setComponentProperty(comp, [args.propertyName], args.value);
|
|
97
|
+
if (!setResult.found) {
|
|
98
|
+
return JSON.stringify({
|
|
99
|
+
ok: false,
|
|
100
|
+
error: "property \"" + args.propertyName + "\" not found on component \"" + compDisplayName + "\""
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return JSON.stringify({
|
|
105
|
+
ok: true,
|
|
106
|
+
result: {
|
|
107
|
+
sequenceName: seq.name,
|
|
108
|
+
trackType: args.trackType,
|
|
109
|
+
trackIndex: args.trackIndex,
|
|
110
|
+
clipIndex: args.clipIndex,
|
|
111
|
+
clipName: clipName,
|
|
112
|
+
componentName: compDisplayName,
|
|
113
|
+
propertyName: args.propertyName,
|
|
114
|
+
valueType: args.valueType,
|
|
115
|
+
previousValue: setResult.previousValue,
|
|
116
|
+
requestedValue: setResult.requestedValue,
|
|
117
|
+
newValue: setResult.newValue,
|
|
118
|
+
verified: setResult.verified
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
} catch (e) {
|
|
122
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
123
|
+
}
|
|
124
|
+
}
|