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,305 @@
|
|
|
1
|
+
// Command: debug-qe-try-mutate → ppb_debugQeTryMutate
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (ensureQEEnabled, ...)
|
|
4
|
+
// are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// TEMPORARY / EXPERIMENTAL — mutation test, not a supported panel feature.
|
|
7
|
+
// Reflection (see ppb_debugQeInspect) revealed method NAMES on QE Clip
|
|
8
|
+
// objects (remove, move, moveToTrack, ...) but no signatures — every
|
|
9
|
+
// method's .reflect description/parameters came back empty on this build.
|
|
10
|
+
// This tries a short list of plausible argument counts for `remove` and
|
|
11
|
+
// `moveToTrack` against real clips and reports what happened, so the real
|
|
12
|
+
// signature can be inferred from behavior instead of guessed blind.
|
|
13
|
+
//
|
|
14
|
+
// SAFETY GUARD: only runs if the *active* sequence's name exactly matches
|
|
15
|
+
// args.sequenceName. Point this at a duplicate/throwaway sequence, never
|
|
16
|
+
// at real project media — a wrong guess could ripple-shift or delete
|
|
17
|
+
// clips on whatever sequence is active.
|
|
18
|
+
function scanAudioClips(qeSeq, numAudioTracks) {
|
|
19
|
+
var clips = [];
|
|
20
|
+
var emptyTrackIndices = [];
|
|
21
|
+
|
|
22
|
+
for (var t = 0; t < numAudioTracks; t++) {
|
|
23
|
+
var track = qeSeq.getAudioTrackAt(t);
|
|
24
|
+
var numItems = track.numItems;
|
|
25
|
+
var allEmpty = true;
|
|
26
|
+
|
|
27
|
+
for (var i = 0; i < numItems; i++) {
|
|
28
|
+
var item = track.getItemAt(i);
|
|
29
|
+
if (item.type !== "Empty") {
|
|
30
|
+
allEmpty = false;
|
|
31
|
+
clips.push({ trackIndex: t, itemIndex: i, name: item.name, item: item });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (allEmpty) {
|
|
36
|
+
emptyTrackIndices.push(t);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { clips: clips, emptyTrackIndices: emptyTrackIndices };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function describeAudioTrack(qeSeq, trackIndex) {
|
|
44
|
+
var track = qeSeq.getAudioTrackAt(trackIndex);
|
|
45
|
+
var items = [];
|
|
46
|
+
for (var i = 0; i < track.numItems; i++) {
|
|
47
|
+
var item = track.getItemAt(i);
|
|
48
|
+
items.push({ index: i, type: item.type, name: item.type !== "Empty" ? item.name : "" });
|
|
49
|
+
}
|
|
50
|
+
return items;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function tryCallGuesses(fn, thisArg, guesses) {
|
|
54
|
+
var attempts = [];
|
|
55
|
+
var succeededWithArgs = null;
|
|
56
|
+
|
|
57
|
+
for (var g = 0; g < guesses.length; g++) {
|
|
58
|
+
var callArgs = guesses[g];
|
|
59
|
+
try {
|
|
60
|
+
fn.apply(thisArg, callArgs);
|
|
61
|
+
attempts.push({ args: describeArgsForLog(callArgs), success: true });
|
|
62
|
+
succeededWithArgs = describeArgsForLog(callArgs);
|
|
63
|
+
break;
|
|
64
|
+
} catch (e) {
|
|
65
|
+
attempts.push({ args: describeArgsForLog(callArgs), success: false, error: e.toString() });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { attempts: attempts, succeededWithArgs: succeededWithArgs };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function describeArgsForLog(callArgs) {
|
|
73
|
+
var described = [];
|
|
74
|
+
for (var i = 0; i < callArgs.length; i++) {
|
|
75
|
+
var a = callArgs[i];
|
|
76
|
+
if (a && typeof a === "object" && typeof a.numItems !== "undefined") {
|
|
77
|
+
described.push("<Track>");
|
|
78
|
+
} else if (a && typeof a === "object" && typeof a.seconds !== "undefined") {
|
|
79
|
+
described.push("<Time seconds=" + a.seconds + ">");
|
|
80
|
+
} else {
|
|
81
|
+
described.push(a);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return described;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function ppb_debugQeTryMutate(argsJson) {
|
|
88
|
+
try {
|
|
89
|
+
var args;
|
|
90
|
+
try {
|
|
91
|
+
args = JSON.parse(argsJson);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!args.sequenceName || typeof args.sequenceName !== "string") {
|
|
97
|
+
return JSON.stringify({ ok: false, error: "sequenceName is required (safety guard — must exactly match the active sequence's name)" });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!app.project) {
|
|
101
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
ensureQEEnabled();
|
|
106
|
+
} catch (e) {
|
|
107
|
+
return JSON.stringify({ ok: false, error: "app.enableQE() failed: " + e.toString() });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
111
|
+
return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
var qeSeq;
|
|
115
|
+
try {
|
|
116
|
+
qeSeq = qe.project.getActiveSequence();
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e.toString() });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!qeSeq) {
|
|
122
|
+
return JSON.stringify({ ok: false, error: "no active sequence (open/select a sequence tab in Premiere)" });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (qeSeq.name !== args.sequenceName) {
|
|
126
|
+
return JSON.stringify({
|
|
127
|
+
ok: false,
|
|
128
|
+
error: "active sequence is \"" + qeSeq.name + "\", expected \"" + args.sequenceName +
|
|
129
|
+
"\" — select the intended duplicate/test sequence's tab in Premiere before running this"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var numAudioTracks = qeSeq.numAudioTracks;
|
|
134
|
+
var scan = scanAudioClips(qeSeq, numAudioTracks);
|
|
135
|
+
|
|
136
|
+
if (scan.clips.length < 1) {
|
|
137
|
+
return JSON.stringify({
|
|
138
|
+
ok: true,
|
|
139
|
+
result: { note: "no audio clips found on any audio track — nothing to test on", numAudioTracks: numAudioTracks }
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
var result = { before: {}, removeTest: null, moveTest: null };
|
|
144
|
+
var skipRemoveTest = args.skipRemoveTest === true;
|
|
145
|
+
var removeTargetTrackIndex = null;
|
|
146
|
+
|
|
147
|
+
if (skipRemoveTest) {
|
|
148
|
+
result.removeTest = { skipped: true, reason: "skipRemoveTest was true" };
|
|
149
|
+
} else {
|
|
150
|
+
// --- remove() test ---
|
|
151
|
+
var removeTarget = scan.clips[0];
|
|
152
|
+
removeTargetTrackIndex = removeTarget.trackIndex;
|
|
153
|
+
result.before.removeTarget = { track: removeTarget.trackIndex, item: removeTarget.itemIndex, name: removeTarget.name };
|
|
154
|
+
|
|
155
|
+
var removeGuesses = [[], [true], [false], [true, true], [true, false], [false, true]];
|
|
156
|
+
var removeOutcome = tryCallGuesses(removeTarget.item.remove, removeTarget.item, removeGuesses);
|
|
157
|
+
|
|
158
|
+
result.removeTest = {
|
|
159
|
+
attempts: removeOutcome.attempts,
|
|
160
|
+
succeededWithArgs: removeOutcome.succeededWithArgs,
|
|
161
|
+
trackAfter: describeAudioTrack(qeSeq, removeTarget.trackIndex)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --- moveToTrack() test — pick a clip on a DIFFERENT track than the
|
|
166
|
+
// remove target (if any), so the two tests don't interfere with each
|
|
167
|
+
// other's track-index bookkeeping.
|
|
168
|
+
var moveTarget = null;
|
|
169
|
+
for (var c = 0; c < scan.clips.length; c++) {
|
|
170
|
+
if (scan.clips[c].trackIndex !== removeTargetTrackIndex) {
|
|
171
|
+
moveTarget = scan.clips[c];
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!moveTarget) {
|
|
177
|
+
result.moveTest = { skipped: true, reason: "only one clip (or all clips on the same track) found; need a second clip on a distinct track" };
|
|
178
|
+
return JSON.stringify({ ok: true, result: result });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
result.before.moveTarget = { track: moveTarget.trackIndex, item: moveTarget.itemIndex, name: moveTarget.name };
|
|
182
|
+
|
|
183
|
+
var destTrackIndex = null;
|
|
184
|
+
for (var e2 = 0; e2 < scan.emptyTrackIndices.length; e2++) {
|
|
185
|
+
if (scan.emptyTrackIndices[e2] !== moveTarget.trackIndex) {
|
|
186
|
+
destTrackIndex = scan.emptyTrackIndices[e2];
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (destTrackIndex === null) {
|
|
192
|
+
result.moveTest = { skipped: true, reason: "no empty audio track available as a safe move destination" };
|
|
193
|
+
return JSON.stringify({ ok: true, result: result });
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
var destTrack = qeSeq.getAudioTrackAt(destTrackIndex);
|
|
197
|
+
|
|
198
|
+
// Prior runs: Track object at position 0 -> "Illegal Parameter type";
|
|
199
|
+
// plain number at position 0 with <3 total args -> "Not Enough
|
|
200
|
+
// Parameters" (count accepted, so a numeric track index IS the right
|
|
201
|
+
// type there). With >=3 plain-number/boolean args, every guess became
|
|
202
|
+
// "Illegal Parameter type" instead -- count is satisfied but some
|
|
203
|
+
// position now fails type-checking. Likely candidate: a "position"
|
|
204
|
+
// argument wants a real Time object, not a raw number. Try constructing
|
|
205
|
+
// one via the global `Time` class (shared with the standard Premiere
|
|
206
|
+
// DOM) and via reusing the moved clip's own `.start` (already a
|
|
207
|
+
// confirmed-valid QETime instance) in that slot instead of `0`.
|
|
208
|
+
var zeroTime = null;
|
|
209
|
+
try {
|
|
210
|
+
zeroTime = new Time();
|
|
211
|
+
zeroTime.seconds = 0;
|
|
212
|
+
} catch (e) {
|
|
213
|
+
zeroTime = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
var clipStartTime = null;
|
|
217
|
+
try {
|
|
218
|
+
clipStartTime = moveTarget.item.start;
|
|
219
|
+
} catch (e) {
|
|
220
|
+
clipStartTime = null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
var moveGuesses = [];
|
|
224
|
+
if (zeroTime !== null) {
|
|
225
|
+
moveGuesses.push([destTrackIndex, zeroTime, 0]);
|
|
226
|
+
moveGuesses.push([destTrackIndex, zeroTime, true]);
|
|
227
|
+
moveGuesses.push([destTrackIndex, zeroTime, false]);
|
|
228
|
+
moveGuesses.push([moveTarget.trackIndex, destTrackIndex, zeroTime]);
|
|
229
|
+
}
|
|
230
|
+
if (clipStartTime !== null) {
|
|
231
|
+
moveGuesses.push([destTrackIndex, clipStartTime, 0]);
|
|
232
|
+
moveGuesses.push([destTrackIndex, clipStartTime, true]);
|
|
233
|
+
moveGuesses.push([moveTarget.trackIndex, destTrackIndex, clipStartTime]);
|
|
234
|
+
}
|
|
235
|
+
// Fallbacks in case neither Time construction path is available.
|
|
236
|
+
moveGuesses.push([destTrackIndex, 0, 0]);
|
|
237
|
+
moveGuesses.push([destTrackIndex, 0, true]);
|
|
238
|
+
|
|
239
|
+
result.moveTest_zeroTimeConstructed = zeroTime !== null;
|
|
240
|
+
result.moveTest_clipStartTimeReadable = clipStartTime !== null;
|
|
241
|
+
|
|
242
|
+
var moveOutcome = tryCallGuesses(moveTarget.item.moveToTrack, moveTarget.item, moveGuesses);
|
|
243
|
+
|
|
244
|
+
result.moveTest = {
|
|
245
|
+
destTrackIndex: destTrackIndex,
|
|
246
|
+
attempts: moveOutcome.attempts,
|
|
247
|
+
succeededWithArgs: moveOutcome.succeededWithArgs,
|
|
248
|
+
sourceTrackAfter: describeAudioTrack(qeSeq, moveTarget.trackIndex),
|
|
249
|
+
destTrackAfter: describeAudioTrack(qeSeq, destTrackIndex)
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// --- Alternative to moveToTrack(): place a NEW instance of the same
|
|
253
|
+
// source clip directly onto the destination track via Track-level
|
|
254
|
+
// insert()/overwrite(), mirroring the standard DOM's documented
|
|
255
|
+
// Track.insertClip(projectItem, time) / overwriteClip(projectItem, time).
|
|
256
|
+
// Doesn't require moving the existing TrackItem at all.
|
|
257
|
+
var projectItem = null;
|
|
258
|
+
try {
|
|
259
|
+
projectItem = moveTarget.item.getProjectItem();
|
|
260
|
+
} catch (e) {
|
|
261
|
+
result.insertOverwriteTest = { skipped: true, reason: "getProjectItem() failed: " + e.toString() };
|
|
262
|
+
return JSON.stringify({ ok: true, result: result });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (!projectItem) {
|
|
266
|
+
result.insertOverwriteTest = { skipped: true, reason: "getProjectItem() returned nothing" };
|
|
267
|
+
return JSON.stringify({ ok: true, result: result });
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
var insertGuesses = [
|
|
271
|
+
[projectItem, zeroTime],
|
|
272
|
+
[projectItem, 0],
|
|
273
|
+
[projectItem],
|
|
274
|
+
[projectItem, zeroTime, 0],
|
|
275
|
+
[projectItem, zeroTime, true]
|
|
276
|
+
];
|
|
277
|
+
var insertOutcome = tryCallGuesses(destTrack.insert, destTrack, insertGuesses);
|
|
278
|
+
|
|
279
|
+
var insertResult = {
|
|
280
|
+
attempts: insertOutcome.attempts,
|
|
281
|
+
succeededWithArgs: insertOutcome.succeededWithArgs,
|
|
282
|
+
destTrackAfterInsert: describeAudioTrack(qeSeq, destTrackIndex)
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// Only try overwrite() if insert() didn't already place something —
|
|
286
|
+
// avoids stacking two clips onto the same (short) destination track.
|
|
287
|
+
if (insertOutcome.succeededWithArgs === null) {
|
|
288
|
+
var overwriteGuesses = [
|
|
289
|
+
[projectItem, zeroTime],
|
|
290
|
+
[projectItem, 0],
|
|
291
|
+
[projectItem]
|
|
292
|
+
];
|
|
293
|
+
var overwriteOutcome = tryCallGuesses(destTrack.overwrite, destTrack, overwriteGuesses);
|
|
294
|
+
insertResult.overwriteAttempts = overwriteOutcome.attempts;
|
|
295
|
+
insertResult.overwriteSucceededWithArgs = overwriteOutcome.succeededWithArgs;
|
|
296
|
+
insertResult.destTrackAfterOverwrite = describeAudioTrack(qeSeq, destTrackIndex);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
result.insertOverwriteTest = insertResult;
|
|
300
|
+
|
|
301
|
+
return JSON.stringify({ ok: true, result: result });
|
|
302
|
+
} catch (e) {
|
|
303
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Command: delete-marker → ppb_deleteMarker
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (TICKS_PER_SECOND,
|
|
4
|
+
// findSequenceByName, timeValueToSeconds, ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ported from leancoderkavy's premiere-pro-mcp delete_marker tool, but
|
|
7
|
+
// re-addressed like update-marker.jsx: identifies the target by .guid
|
|
8
|
+
// rather than matching a time value within a tolerance window. Deletion
|
|
9
|
+
// itself is markers.deleteMarker(marker) per PREMIERE_API_NOTES.md.
|
|
10
|
+
//
|
|
11
|
+
// Also accepts PROJECT-ITEM addressing (nodeId or itemName instead of
|
|
12
|
+
// sequenceName) to delete markers created by add-marker-to-project-item —
|
|
13
|
+
// needed because undo is non-functional on this Premiere 2026 build
|
|
14
|
+
// (app.project.undo missing; qe.project.undo is a confirmed silent no-op),
|
|
15
|
+
// so item markers would otherwise be undeletable from the bridge.
|
|
16
|
+
//
|
|
17
|
+
// MUTATION RULE: verified by comparing the collection's total marker count
|
|
18
|
+
// before and after (must drop by exactly one) AND confirming the guid no
|
|
19
|
+
// longer appears in a fresh getFirstMarker()/getNextMarker() walk — never
|
|
20
|
+
// trusting deleteMarker()'s own (lack of a) return value.
|
|
21
|
+
|
|
22
|
+
function ppbDeleteMarker_findByGuidAndCount(markerCollection, guid, markerName) {
|
|
23
|
+
var found = null;
|
|
24
|
+
var matches = 0;
|
|
25
|
+
var count = 0;
|
|
26
|
+
var m = markerCollection.getFirstMarker();
|
|
27
|
+
var iterations = 0;
|
|
28
|
+
while (m !== null && typeof m !== "undefined" && iterations < 10000) {
|
|
29
|
+
count++;
|
|
30
|
+
var thisGuid = null;
|
|
31
|
+
var thisName = null;
|
|
32
|
+
try { thisGuid = m.guid; } catch (e) { thisGuid = null; }
|
|
33
|
+
try { thisName = m.name; } catch (e) { thisName = null; }
|
|
34
|
+
var isMatch = (guid !== null && thisGuid === guid) ||
|
|
35
|
+
(guid === null && markerName !== null && thisName === markerName);
|
|
36
|
+
if (isMatch) {
|
|
37
|
+
found = m;
|
|
38
|
+
matches++;
|
|
39
|
+
}
|
|
40
|
+
m = markerCollection.getNextMarker(m);
|
|
41
|
+
iterations++;
|
|
42
|
+
}
|
|
43
|
+
return { found: found, count: count, matches: matches };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Depth-first project-item lookup by nodeId or exact name (same approach
|
|
47
|
+
// as get-project-item-info's walker: recurse on children presence, NOT on
|
|
48
|
+
// isBin — the root item's type is ROOT).
|
|
49
|
+
function ppbDeleteMarker_findItem(item, nodeId, name, depth) {
|
|
50
|
+
if (depth > 32) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
if (nodeId !== null && item.nodeId === nodeId) {
|
|
55
|
+
return item;
|
|
56
|
+
}
|
|
57
|
+
if (name !== null && item.name === name && item.type !== ProjectItemType.BIN && item.type !== ProjectItemType.ROOT) {
|
|
58
|
+
return item;
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// fall through
|
|
62
|
+
}
|
|
63
|
+
if (item.children && item.children.numItems > 0) {
|
|
64
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
65
|
+
var found = ppbDeleteMarker_findItem(item.children[i], nodeId, name, depth + 1);
|
|
66
|
+
if (found) {
|
|
67
|
+
return found;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function ppb_deleteMarker(argsJson) {
|
|
75
|
+
try {
|
|
76
|
+
var args;
|
|
77
|
+
try {
|
|
78
|
+
args = JSON.parse(argsJson);
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var hasGuid = typeof args.guid === "string" && args.guid.length > 0;
|
|
84
|
+
var hasMarkerName = typeof args.markerName === "string" && args.markerName.length > 0;
|
|
85
|
+
if (!hasGuid && !hasMarkerName) {
|
|
86
|
+
return JSON.stringify({ ok: false, error: "one of guid or markerName is required" });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!app.project) {
|
|
90
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
var hasItemAddress = (typeof args.nodeId === "string" && args.nodeId.length > 0) ||
|
|
94
|
+
(typeof args.itemName === "string" && args.itemName.length > 0);
|
|
95
|
+
|
|
96
|
+
var markerCollection = null;
|
|
97
|
+
var scopeLabel = null;
|
|
98
|
+
|
|
99
|
+
if (hasItemAddress) {
|
|
100
|
+
// Project-item marker deletion
|
|
101
|
+
var item = ppbDeleteMarker_findItem(
|
|
102
|
+
app.project.rootItem,
|
|
103
|
+
(typeof args.nodeId === "string" && args.nodeId.length > 0) ? args.nodeId : null,
|
|
104
|
+
(typeof args.itemName === "string" && args.itemName.length > 0) ? args.itemName : null,
|
|
105
|
+
0
|
|
106
|
+
);
|
|
107
|
+
if (!item) {
|
|
108
|
+
return JSON.stringify({ ok: false, error: "no project item found matching the given nodeId/itemName" });
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
markerCollection = item.getMarkers();
|
|
112
|
+
} catch (e) {
|
|
113
|
+
return JSON.stringify({ ok: false, error: "getMarkers() failed on the project item: " + e.toString() });
|
|
114
|
+
}
|
|
115
|
+
scopeLabel = item.name;
|
|
116
|
+
} else {
|
|
117
|
+
var seq = null;
|
|
118
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
119
|
+
seq = findSequenceByName(args.sequenceName);
|
|
120
|
+
if (!seq) {
|
|
121
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
seq = app.project.activeSequence;
|
|
125
|
+
if (!seq) {
|
|
126
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
markerCollection = seq.markers;
|
|
130
|
+
scopeLabel = seq.name;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var guidArg = hasGuid ? args.guid : null;
|
|
134
|
+
var nameArg = hasMarkerName ? args.markerName : null;
|
|
135
|
+
var before = ppbDeleteMarker_findByGuidAndCount(markerCollection, guidArg, nameArg);
|
|
136
|
+
if (!before.found) {
|
|
137
|
+
return JSON.stringify({ ok: false, error: "no marker found matching " + (hasGuid ? "guid \"" + args.guid + "\"" : "name \"" + args.markerName + "\"") + " on " + scopeLabel });
|
|
138
|
+
}
|
|
139
|
+
if (!hasGuid && before.matches > 1) {
|
|
140
|
+
return JSON.stringify({ ok: false, error: before.matches + " markers named \"" + args.markerName + "\" on " + scopeLabel + " — use --guid to disambiguate" });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
markerCollection.deleteMarker(before.found);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
return JSON.stringify({ ok: false, error: "deleteMarker failed: " + e.toString() });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var after = ppbDeleteMarker_findByGuidAndCount(markerCollection, guidArg, nameArg);
|
|
150
|
+
|
|
151
|
+
var deleted = after.found === null && after.count === before.count - 1;
|
|
152
|
+
|
|
153
|
+
if (!deleted) {
|
|
154
|
+
return JSON.stringify({
|
|
155
|
+
ok: false,
|
|
156
|
+
error: "deleteMarker did not throw, but the marker count/guid check afterward doesn't confirm deletion",
|
|
157
|
+
countBefore: before.count,
|
|
158
|
+
countAfter: after.count,
|
|
159
|
+
stillPresent: after.found !== null
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return JSON.stringify({
|
|
164
|
+
ok: true,
|
|
165
|
+
result: {
|
|
166
|
+
scope: hasItemAddress ? "projectItem" : "sequence",
|
|
167
|
+
scopeName: scopeLabel,
|
|
168
|
+
deleted: true,
|
|
169
|
+
guid: hasGuid ? args.guid : null,
|
|
170
|
+
markerName: hasMarkerName ? args.markerName : null,
|
|
171
|
+
markerCountBefore: before.count,
|
|
172
|
+
markerCountAfter: after.count
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
} catch (e) {
|
|
176
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Command: deselect-all-clips → ppb_deselectAllClips
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// timeValueToSeconds, ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Standard-DOM only (clip.setSelected(false, true)) — no QE needed. Ported
|
|
7
|
+
// from leancoderkavy's premiere-pro-mcp `deselect_all_clips` tool
|
|
8
|
+
// (selection.ts). Mutation — verified via seq.getSelection() afterward
|
|
9
|
+
// (expected to read back empty).
|
|
10
|
+
|
|
11
|
+
function ppb_deselectAllClipsCollectSelection(seq) {
|
|
12
|
+
var sel = null;
|
|
13
|
+
try {
|
|
14
|
+
sel = seq.getSelection();
|
|
15
|
+
} catch (e) {
|
|
16
|
+
sel = null;
|
|
17
|
+
}
|
|
18
|
+
var selCount = 0;
|
|
19
|
+
if (sel) {
|
|
20
|
+
if (typeof sel.numItems === "number") {
|
|
21
|
+
selCount = sel.numItems;
|
|
22
|
+
} else if (typeof sel.length === "number") {
|
|
23
|
+
selCount = sel.length;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var selectedClips = [];
|
|
27
|
+
var cap = selCount > 20 ? 20 : selCount;
|
|
28
|
+
for (var i = 0; i < cap; i++) {
|
|
29
|
+
var item = sel[i];
|
|
30
|
+
var entry = { name: null, mediaType: null, startSeconds: null, endSeconds: null, nodeId: null };
|
|
31
|
+
try { entry.name = item.name; } catch (e) { entry.name = null; }
|
|
32
|
+
try { entry.mediaType = item.mediaType; } catch (e) { entry.mediaType = null; }
|
|
33
|
+
try { entry.startSeconds = timeValueToSeconds(item.start); } catch (e) { entry.startSeconds = null; }
|
|
34
|
+
try { entry.endSeconds = timeValueToSeconds(item.end); } catch (e) { entry.endSeconds = null; }
|
|
35
|
+
try { entry.nodeId = item.nodeId; } catch (e) { entry.nodeId = null; }
|
|
36
|
+
selectedClips.push(entry);
|
|
37
|
+
}
|
|
38
|
+
var result = { selectedCount: selCount, selectedClips: selectedClips };
|
|
39
|
+
if (selCount > 20) {
|
|
40
|
+
result.truncated = true;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ppb_deselectAllClips(argsJson) {
|
|
46
|
+
try {
|
|
47
|
+
var args;
|
|
48
|
+
try {
|
|
49
|
+
args = JSON.parse(argsJson);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!app.project) {
|
|
55
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var seq = null;
|
|
59
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
60
|
+
seq = findSequenceByName(args.sequenceName);
|
|
61
|
+
if (!seq) {
|
|
62
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
seq = app.project.activeSequence;
|
|
66
|
+
if (!seq) {
|
|
67
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function deselectAllInTracks(tracks) {
|
|
72
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
73
|
+
var track = tracks[t];
|
|
74
|
+
for (var c = 0; c < track.clips.numItems; c++) {
|
|
75
|
+
try { track.clips[c].setSelected(false, true); } catch (e) { /* best-effort */ }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
deselectAllInTracks(seq.videoTracks);
|
|
81
|
+
deselectAllInTracks(seq.audioTracks);
|
|
82
|
+
|
|
83
|
+
var selectionResult = ppb_deselectAllClipsCollectSelection(seq);
|
|
84
|
+
|
|
85
|
+
var result = {
|
|
86
|
+
sequenceName: seq.name
|
|
87
|
+
};
|
|
88
|
+
result.selectedCount = selectionResult.selectedCount;
|
|
89
|
+
result.selectedClips = selectionResult.selectedClips;
|
|
90
|
+
if (selectionResult.truncated) {
|
|
91
|
+
result.truncated = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return JSON.stringify({ ok: true, result: result });
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Command: detach-proxy → ppb_detachProxy
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (TICKS_PER_SECOND, ...)
|
|
4
|
+
// are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ports the reference project's media.ts detach_proxy tool. Item
|
|
7
|
+
// resolution by nodeId/name uses children-presence recursion (NOT an
|
|
8
|
+
// isBin() gate), per get-project-item-info.jsx's live-debugged finding.
|
|
9
|
+
// Checks hasProxy() first and fails honestly if no proxy is attached,
|
|
10
|
+
// rather than calling detachProxy() unconditionally. Verified via a
|
|
11
|
+
// hasProxy() read-back (expected false afterward).
|
|
12
|
+
|
|
13
|
+
function ppbDetachProxy_findByNodeId(item, nodeId, depth) {
|
|
14
|
+
if (depth > 32) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
if (item.nodeId === nodeId) {
|
|
19
|
+
return item;
|
|
20
|
+
}
|
|
21
|
+
} catch (e) {
|
|
22
|
+
// fall through
|
|
23
|
+
}
|
|
24
|
+
if (item.children && item.children.numItems > 0) {
|
|
25
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
26
|
+
var found = ppbDetachProxy_findByNodeId(item.children[i], nodeId, depth + 1);
|
|
27
|
+
if (found) {
|
|
28
|
+
return found;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function ppbDetachProxy_findByName(item, name, depth) {
|
|
36
|
+
if (depth > 32) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
if (item.name === name) {
|
|
41
|
+
return item;
|
|
42
|
+
}
|
|
43
|
+
} catch (e) {
|
|
44
|
+
// fall through
|
|
45
|
+
}
|
|
46
|
+
if (item.children && item.children.numItems > 0) {
|
|
47
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
48
|
+
var found = ppbDetachProxy_findByName(item.children[i], name, depth + 1);
|
|
49
|
+
if (found) {
|
|
50
|
+
return found;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ppb_detachProxy(argsJson) {
|
|
58
|
+
try {
|
|
59
|
+
var args;
|
|
60
|
+
try {
|
|
61
|
+
args = JSON.parse(argsJson);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var hasNodeId = typeof args.nodeId === "string" && args.nodeId.length > 0;
|
|
67
|
+
var hasName = typeof args.name === "string" && args.name.length > 0;
|
|
68
|
+
if (!hasNodeId && !hasName) {
|
|
69
|
+
return JSON.stringify({ ok: false, error: "either nodeId or name is required" });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!app.project) {
|
|
73
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var item = hasNodeId
|
|
77
|
+
? ppbDetachProxy_findByNodeId(app.project.rootItem, args.nodeId, 0)
|
|
78
|
+
: ppbDetachProxy_findByName(app.project.rootItem, args.name, 0);
|
|
79
|
+
if (!item) {
|
|
80
|
+
return JSON.stringify({ ok: false, error: "no project item found matching the given nodeId/name" });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var hadProxy = null;
|
|
84
|
+
try { hadProxy = item.hasProxy(); } catch (e) { hadProxy = null; }
|
|
85
|
+
if (hadProxy === false) {
|
|
86
|
+
return JSON.stringify({
|
|
87
|
+
ok: false,
|
|
88
|
+
error: "hasProxy() returned false — no proxy is attached to this item",
|
|
89
|
+
nodeId: item.nodeId,
|
|
90
|
+
name: item.name
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
item.detachProxy();
|
|
96
|
+
} catch (e) {
|
|
97
|
+
return JSON.stringify({ ok: false, error: "detachProxy() failed: " + e.toString() });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
var hasProxyAfter = null;
|
|
101
|
+
try { hasProxyAfter = item.hasProxy(); } catch (e) { hasProxyAfter = null; }
|
|
102
|
+
|
|
103
|
+
return JSON.stringify({
|
|
104
|
+
ok: true,
|
|
105
|
+
result: {
|
|
106
|
+
nodeId: item.nodeId,
|
|
107
|
+
name: item.name,
|
|
108
|
+
hadProxy: hadProxy,
|
|
109
|
+
hasProxyAfter: hasProxyAfter,
|
|
110
|
+
verified: hasProxyAfter === false
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} catch (e) {
|
|
114
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
115
|
+
}
|
|
116
|
+
}
|