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,162 @@
|
|
|
1
|
+
// Command: roll-edit → ppb_rollEdit
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// ensureQEEnabled, activateSequenceForQE, resolveTimelineClip,
|
|
5
|
+
// resolveQeClip, serializeTrackItem, TICKS_PER_SECOND, ...) are already
|
|
6
|
+
// defined there.
|
|
7
|
+
//
|
|
8
|
+
// Rolls the edit point between the addressed clip and its neighbor —
|
|
9
|
+
// moves the shared cut point in time WITHOUT changing the overall
|
|
10
|
+
// sequence duration (one clip's out point and the next clip's in point
|
|
11
|
+
// move together). Ported from leancoderkavy's premiere-pro-mcp
|
|
12
|
+
// `roll_edit` tool (advanced.ts: `qeClip.roll(offsetTicksString)`), whose
|
|
13
|
+
// signature is UNCONFIRMED on this build (`roll` is on our own reflect
|
|
14
|
+
// list per QE_DOM_NOTES.md/PREMIERE_API_NOTES.md, but never live-called)
|
|
15
|
+
// — every plausible argument form is tried in turn (ticks string, then a
|
|
16
|
+
// raw seconds number, then a Time object), recording an `attempts` array,
|
|
17
|
+
// and success is judged by an actual before/after change in the clip's
|
|
18
|
+
// own end time, never by whether the call merely avoided throwing.
|
|
19
|
+
// Positive offsetSeconds rolls the edit point later (per the reference
|
|
20
|
+
// tool's convention); negative rolls it earlier.
|
|
21
|
+
|
|
22
|
+
function ppbRollEdit_offsetForms(offsetSeconds) {
|
|
23
|
+
var ticksString = String(Math.round(offsetSeconds * TICKS_PER_SECOND));
|
|
24
|
+
var timeObj = null;
|
|
25
|
+
try {
|
|
26
|
+
timeObj = new Time();
|
|
27
|
+
timeObj.seconds = offsetSeconds;
|
|
28
|
+
} catch (e) {
|
|
29
|
+
timeObj = null;
|
|
30
|
+
}
|
|
31
|
+
var forms = [
|
|
32
|
+
{ label: "ticksString", value: ticksString },
|
|
33
|
+
{ label: "seconds", value: offsetSeconds }
|
|
34
|
+
];
|
|
35
|
+
if (timeObj !== null) {
|
|
36
|
+
forms.push({ label: "TimeObject", value: timeObj });
|
|
37
|
+
}
|
|
38
|
+
return forms;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ppb_rollEdit(argsJson) {
|
|
42
|
+
try {
|
|
43
|
+
var args;
|
|
44
|
+
try {
|
|
45
|
+
args = JSON.parse(argsJson);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
51
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
52
|
+
}
|
|
53
|
+
if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
|
|
54
|
+
return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
|
|
55
|
+
}
|
|
56
|
+
if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
|
|
57
|
+
return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
|
|
58
|
+
}
|
|
59
|
+
if (typeof args.offsetSeconds !== "number" || isNaN(args.offsetSeconds) || args.offsetSeconds === 0) {
|
|
60
|
+
return JSON.stringify({ ok: false, error: "offsetSeconds must be a non-zero number" });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!app.project) {
|
|
64
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var seq = null;
|
|
68
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
69
|
+
seq = findSequenceByName(args.sequenceName);
|
|
70
|
+
if (!seq) {
|
|
71
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
seq = app.project.activeSequence;
|
|
75
|
+
if (!seq) {
|
|
76
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var resolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
|
|
81
|
+
if (resolved.error) {
|
|
82
|
+
return JSON.stringify({ ok: false, error: resolved.error });
|
|
83
|
+
}
|
|
84
|
+
var before = serializeTrackItem(resolved.clip, args.trackIndex, args.clipIndex);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
ensureQEEnabled();
|
|
88
|
+
activateSequenceForQE(seq);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return JSON.stringify({ ok: false, error: "app.enableQE()/sequence activation failed: " + e.toString() });
|
|
91
|
+
}
|
|
92
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
93
|
+
return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
var qeSeq;
|
|
97
|
+
try {
|
|
98
|
+
qeSeq = qe.project.getActiveSequence();
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() failed: " + e.toString() });
|
|
101
|
+
}
|
|
102
|
+
var qeResolved = resolveQeClip(qeSeq, args.trackType, args.trackIndex, args.clipIndex);
|
|
103
|
+
if (qeResolved.error) {
|
|
104
|
+
return JSON.stringify({ ok: false, error: qeResolved.error });
|
|
105
|
+
}
|
|
106
|
+
var qeClip = qeResolved.qeClip;
|
|
107
|
+
|
|
108
|
+
if (typeof qeClip.roll !== "function") {
|
|
109
|
+
return JSON.stringify({ ok: false, error: "qeClip.roll is not available on this Premiere build" });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var attempts = [];
|
|
113
|
+
var forms = ppbRollEdit_offsetForms(args.offsetSeconds);
|
|
114
|
+
var succeeded = false;
|
|
115
|
+
var formUsed = null;
|
|
116
|
+
for (var i = 0; i < forms.length && !succeeded; i++) {
|
|
117
|
+
try {
|
|
118
|
+
qeClip.roll(forms[i].value);
|
|
119
|
+
attempts.push({ form: forms[i].label, success: true });
|
|
120
|
+
succeeded = true;
|
|
121
|
+
formUsed = forms[i].label;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
attempts.push({ form: forms[i].label, success: false, error: e.toString() });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!succeeded) {
|
|
128
|
+
return JSON.stringify({
|
|
129
|
+
ok: false,
|
|
130
|
+
error: "qeClip.roll() failed with every argument form tried",
|
|
131
|
+
attempts: attempts
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
var afterResolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
|
|
136
|
+
var after = afterResolved.clip ? serializeTrackItem(afterResolved.clip, args.trackIndex, args.clipIndex) : null;
|
|
137
|
+
|
|
138
|
+
var endDelta = (after && before && after.endSeconds !== null && before.endSeconds !== null)
|
|
139
|
+
? (after.endSeconds - before.endSeconds)
|
|
140
|
+
: null;
|
|
141
|
+
|
|
142
|
+
return JSON.stringify({
|
|
143
|
+
ok: true,
|
|
144
|
+
result: {
|
|
145
|
+
sequenceName: seq.name,
|
|
146
|
+
trackType: args.trackType,
|
|
147
|
+
trackIndex: args.trackIndex,
|
|
148
|
+
clipIndex: args.clipIndex,
|
|
149
|
+
requestedOffsetSeconds: args.offsetSeconds,
|
|
150
|
+
formUsed: formUsed,
|
|
151
|
+
attempts: attempts,
|
|
152
|
+
before: before,
|
|
153
|
+
after: after,
|
|
154
|
+
endSecondsDelta: endDelta,
|
|
155
|
+
verified: endDelta !== null && Math.abs(endDelta - args.offsetSeconds) < 0.5,
|
|
156
|
+
note: "verified compares the clip's own end-time shift against the requested offset within half a second — roll's exact per-neighbor semantics are unconfirmed on this build (see PREMIERE_API_NOTES.md)."
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Command: save-project-as → ppb_saveProjectAs
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context.
|
|
4
|
+
//
|
|
5
|
+
// Ported from leancoderkavy/premiere-pro-mcp's project.ts save_project_as.
|
|
6
|
+
// Calls app.project.saveAs(path). NOTE: this switches the currently OPEN
|
|
7
|
+
// project (app.project) to point at the new file — it is not a "save a
|
|
8
|
+
// copy" operation. Verified by reading app.project.path back afterward
|
|
9
|
+
// and confirming it now matches the requested path.
|
|
10
|
+
|
|
11
|
+
function ppb_saveProjectAs(argsJson) {
|
|
12
|
+
try {
|
|
13
|
+
var args;
|
|
14
|
+
try {
|
|
15
|
+
args = JSON.parse(argsJson);
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!args.path || typeof args.path !== "string") {
|
|
21
|
+
return JSON.stringify({ ok: false, error: "path is required" });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!app.project) {
|
|
25
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
app.project.saveAs(args.path);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "app.project.saveAs() failed: " + e.toString() });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var newPath = null;
|
|
35
|
+
var newName = null;
|
|
36
|
+
try { newPath = app.project.path; } catch (e) { newPath = null; }
|
|
37
|
+
try { newName = app.project.name; } catch (e) { newName = null; }
|
|
38
|
+
|
|
39
|
+
var verified = newPath !== null && newPath === args.path;
|
|
40
|
+
|
|
41
|
+
return JSON.stringify({
|
|
42
|
+
ok: true,
|
|
43
|
+
result: {
|
|
44
|
+
saved: true,
|
|
45
|
+
requestedPath: args.path,
|
|
46
|
+
path: newPath,
|
|
47
|
+
name: newName,
|
|
48
|
+
verified: verified,
|
|
49
|
+
note: "saveAs() switches the currently open project to the new file — the original file on disk is untouched but is no longer what app.project refers to"
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Command: save-project → ppb_saveProject
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context.
|
|
4
|
+
//
|
|
5
|
+
// Ported from leancoderkavy/premiere-pro-mcp's project.ts save_project.
|
|
6
|
+
// Calls app.project.save() (no args — saves to the project's current
|
|
7
|
+
// path). Verification is best-effort: if this Premiere build exposes
|
|
8
|
+
// project.isDirty() (unconfirmed, not documented in
|
|
9
|
+
// PREMIERE_API_NOTES.md), it's read before and after and the command
|
|
10
|
+
// only reports success if it went from dirty to clean; if isDirty isn't
|
|
11
|
+
// available, verification degrades to call-level only (no throw), and
|
|
12
|
+
// `verified` is reported as null with a note rather than a false claim.
|
|
13
|
+
|
|
14
|
+
function ppb_saveProject(argsJson) {
|
|
15
|
+
try {
|
|
16
|
+
if (!app.project) {
|
|
17
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var hasIsDirty = typeof app.project.isDirty === "function";
|
|
21
|
+
var dirtyBefore = null;
|
|
22
|
+
if (hasIsDirty) {
|
|
23
|
+
try { dirtyBefore = app.project.isDirty(); } catch (e) { dirtyBefore = null; }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
app.project.save();
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return JSON.stringify({ ok: false, error: "app.project.save() failed: " + e.toString() });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var dirtyAfter = null;
|
|
33
|
+
if (hasIsDirty) {
|
|
34
|
+
try { dirtyAfter = app.project.isDirty(); } catch (e) { dirtyAfter = null; }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var verified = null;
|
|
38
|
+
var note = null;
|
|
39
|
+
if (hasIsDirty && dirtyBefore !== null && dirtyAfter !== null) {
|
|
40
|
+
verified = dirtyAfter === false;
|
|
41
|
+
} else {
|
|
42
|
+
note = "isDirty() is not available (or not readable) on this Premiere build — verification is call-level only (save() did not throw)";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var name = null;
|
|
46
|
+
var path = null;
|
|
47
|
+
try { name = app.project.name; } catch (e) { name = null; }
|
|
48
|
+
try { path = app.project.path; } catch (e) { path = null; }
|
|
49
|
+
|
|
50
|
+
return JSON.stringify({
|
|
51
|
+
ok: true,
|
|
52
|
+
result: { saved: true, name: name, path: path, verified: verified, note: note }
|
|
53
|
+
});
|
|
54
|
+
} catch (e) {
|
|
55
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Command: scene-edit-detection → ppb_sceneEditDetection
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ported from leancoderkavy/premiere-pro-mcp's advanced.ts
|
|
7
|
+
// scene_edit_detection tool, expanded per PREMIERE_API_NOTES.md's fuller
|
|
8
|
+
// signature: `seq.performSceneEditDetectionOnSelection(mode, applyToLinked
|
|
9
|
+
// AudioBool, sensitivity)` where mode is "ApplyCuts"|"CreateMarkers" and
|
|
10
|
+
// sensitivity is "Low"|"Medium"|"High" (the reference tool's own handler
|
|
11
|
+
// calls the zero-arg form, dropping all three).
|
|
12
|
+
//
|
|
13
|
+
// ⚠️ OPERATES ON THE CURRENT SELECTION, not the whole sequence — same
|
|
14
|
+
// selection precondition as nest-clips.jsx. This command refuses outright
|
|
15
|
+
// if nothing is selected rather than letting Premiere silently no-op, and
|
|
16
|
+
// reports selectedClipCount so callers know what was actually processed.
|
|
17
|
+
// Marker counts are read before/after only for "CreateMarkers" mode;
|
|
18
|
+
// "ApplyCuts" mode's razor-cut effect is not independently verified here
|
|
19
|
+
// (scene detection can run asynchronously, same caveat as
|
|
20
|
+
// stabilize-clip.jsx's Warp Stabilizer analysis).
|
|
21
|
+
function ppb_sceneEditDetection(argsJson) {
|
|
22
|
+
try {
|
|
23
|
+
var args;
|
|
24
|
+
try {
|
|
25
|
+
args = JSON.parse(argsJson);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!app.project) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var validModes = { ApplyCuts: true, CreateMarkers: true };
|
|
35
|
+
if (!args.mode || !validModes[args.mode]) {
|
|
36
|
+
return JSON.stringify({ ok: false, error: "mode must be one of ApplyCuts, CreateMarkers" });
|
|
37
|
+
}
|
|
38
|
+
if (typeof args.applyToLinkedAudio !== "boolean") {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "applyToLinkedAudio (boolean) is required" });
|
|
40
|
+
}
|
|
41
|
+
var validSensitivities = { Low: true, Medium: true, High: true };
|
|
42
|
+
if (!args.sensitivity || !validSensitivities[args.sensitivity]) {
|
|
43
|
+
return JSON.stringify({ ok: false, error: "sensitivity must be one of Low, Medium, High" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var seq;
|
|
47
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
48
|
+
seq = findSequenceByName(args.sequenceName);
|
|
49
|
+
if (!seq) {
|
|
50
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
seq = app.project.activeSequence;
|
|
54
|
+
if (!seq) {
|
|
55
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (app.project.activeSequence !== seq) {
|
|
59
|
+
app.project.activeSequence = seq;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var selectedCount = 0;
|
|
63
|
+
function countSelected(tracks) {
|
|
64
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
65
|
+
for (var c = 0; c < tracks[t].clips.numItems; c++) {
|
|
66
|
+
var isSel = false;
|
|
67
|
+
try { isSel = tracks[t].clips[c].isSelected(); } catch (e) { isSel = false; }
|
|
68
|
+
if (isSel) {
|
|
69
|
+
selectedCount++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
countSelected(seq.videoTracks);
|
|
75
|
+
countSelected(seq.audioTracks);
|
|
76
|
+
|
|
77
|
+
if (selectedCount === 0) {
|
|
78
|
+
return JSON.stringify({
|
|
79
|
+
ok: false,
|
|
80
|
+
error: "no clips selected — this operation runs on the current SELECTION (select clips first, e.g. select-clips-by-name/select-all-clips)"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function countMarkers() {
|
|
85
|
+
var n = 0;
|
|
86
|
+
var m = seq.markers.getFirstMarker();
|
|
87
|
+
while (m) {
|
|
88
|
+
n++;
|
|
89
|
+
m = seq.markers.getNextMarker(m);
|
|
90
|
+
}
|
|
91
|
+
return n;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var markerCountBefore = null;
|
|
95
|
+
try { markerCountBefore = countMarkers(); } catch (e) { markerCountBefore = null; }
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
seq.performSceneEditDetectionOnSelection(args.mode, args.applyToLinkedAudio, args.sensitivity);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return JSON.stringify({
|
|
101
|
+
ok: false,
|
|
102
|
+
error: "seq.performSceneEditDetectionOnSelection() failed: " + e.toString(),
|
|
103
|
+
selectedClipCount: selectedCount
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
var markerCountAfter = null;
|
|
108
|
+
if (args.mode === "CreateMarkers") {
|
|
109
|
+
try { markerCountAfter = countMarkers(); } catch (e) { markerCountAfter = null; }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return JSON.stringify({
|
|
113
|
+
ok: true,
|
|
114
|
+
result: {
|
|
115
|
+
sequenceName: seq.name,
|
|
116
|
+
mode: args.mode,
|
|
117
|
+
applyToLinkedAudio: args.applyToLinkedAudio,
|
|
118
|
+
sensitivity: args.sensitivity,
|
|
119
|
+
selectedClipCount: selectedCount,
|
|
120
|
+
markerCountBefore: markerCountBefore,
|
|
121
|
+
markerCountAfter: markerCountAfter,
|
|
122
|
+
note: "operates on the current SELECTION, not the whole sequence. ApplyCuts mode's razor-cut effect is not independently verified here (scene detection may run asynchronously); markerCountAfter is only populated for CreateMarkers mode."
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} catch (e) {
|
|
126
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Command: search-project-items → ppb_searchProjectItems
|
|
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
|
+
// ensureQEEnabled, findSequenceByName, ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Recursive walk of the whole project item tree (same shape as
|
|
7
|
+
// list-project-items.jsx's walk), skipping bins for matching purposes but
|
|
8
|
+
// always recursing through them. A matching item must satisfy ALL given
|
|
9
|
+
// filters. Helper names are prefixed ppbSearchItems_ to avoid colliding
|
|
10
|
+
// with same-purpose helpers in other lazily-loaded command files
|
|
11
|
+
// evaluated into this same global context.
|
|
12
|
+
|
|
13
|
+
function ppbSearchItems_extOf(mediaPath) {
|
|
14
|
+
if (!mediaPath || typeof mediaPath !== "string") {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
var dot = mediaPath.lastIndexOf(".");
|
|
18
|
+
if (dot === -1 || dot === mediaPath.length - 1) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return mediaPath.substring(dot + 1).toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function ppbSearchItems_normalizeExtFilter(extension) {
|
|
25
|
+
var e = extension.toLowerCase();
|
|
26
|
+
if (e.charAt(0) === ".") {
|
|
27
|
+
e = e.substring(1);
|
|
28
|
+
}
|
|
29
|
+
return e;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function ppbSearchItems_isBin(item) {
|
|
33
|
+
try {
|
|
34
|
+
return typeof ProjectItemType !== "undefined" && item.type === ProjectItemType.BIN;
|
|
35
|
+
} catch (e) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Capped at depth 32 to defend against pathological/circular bin
|
|
41
|
+
// structures rather than looping forever. errorHolder.error is set (and
|
|
42
|
+
// the walk aborted) only when a colorLabel filter was requested AND
|
|
43
|
+
// getColorLabel() isn't available on this Premiere build.
|
|
44
|
+
function ppbSearchItems_walk(item, parentPath, depth, filters, results, errorHolder) {
|
|
45
|
+
if (depth > 32 || errorHolder.error) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
var treePath = null;
|
|
50
|
+
try {
|
|
51
|
+
treePath = item.treePath;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
treePath = null;
|
|
54
|
+
}
|
|
55
|
+
if (!treePath) {
|
|
56
|
+
treePath = parentPath + "/" + item.name;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var isBin = ppbSearchItems_isBin(item);
|
|
60
|
+
|
|
61
|
+
if (!isBin) {
|
|
62
|
+
var mediaPath = null;
|
|
63
|
+
try {
|
|
64
|
+
mediaPath = item.getMediaPath();
|
|
65
|
+
} catch (e) {
|
|
66
|
+
mediaPath = null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
var isOffline = false;
|
|
70
|
+
try {
|
|
71
|
+
isOffline = item.isOffline();
|
|
72
|
+
} catch (e) {
|
|
73
|
+
isOffline = false;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var colorLabel = null;
|
|
77
|
+
var colorLabelAvailable = true;
|
|
78
|
+
try {
|
|
79
|
+
colorLabel = item.getColorLabel();
|
|
80
|
+
} catch (e) {
|
|
81
|
+
colorLabelAvailable = false;
|
|
82
|
+
colorLabel = null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (filters.colorLabel !== null && !colorLabelAvailable) {
|
|
86
|
+
errorHolder.error = "getColorLabel is not available on this Premiere build";
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var matches = true;
|
|
91
|
+
|
|
92
|
+
if (filters.nameContains !== null && item.name.toLowerCase().indexOf(filters.nameContains) === -1) {
|
|
93
|
+
matches = false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (matches && filters.extension !== null) {
|
|
97
|
+
var ext = ppbSearchItems_extOf(mediaPath);
|
|
98
|
+
if (ext !== filters.extension) {
|
|
99
|
+
matches = false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (matches && filters.offlineOnly === true && !isOffline) {
|
|
104
|
+
matches = false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (matches && filters.colorLabel !== null && colorLabel !== filters.colorLabel) {
|
|
108
|
+
matches = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (matches) {
|
|
112
|
+
results.push({
|
|
113
|
+
name: item.name,
|
|
114
|
+
treePath: treePath,
|
|
115
|
+
nodeId: item.nodeId,
|
|
116
|
+
mediaPath: mediaPath,
|
|
117
|
+
isOffline: isOffline,
|
|
118
|
+
colorLabel: colorLabel
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (isBin && item.children) {
|
|
124
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
125
|
+
ppbSearchItems_walk(item.children[i], treePath, depth + 1, filters, results, errorHolder);
|
|
126
|
+
if (errorHolder.error) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function ppb_searchProjectItems(argsJson) {
|
|
134
|
+
try {
|
|
135
|
+
var args;
|
|
136
|
+
try {
|
|
137
|
+
args = JSON.parse(argsJson);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var hasNameContains = typeof args.nameContains === "string" && args.nameContains.length > 0;
|
|
143
|
+
var hasExtension = typeof args.extension === "string" && args.extension.length > 0;
|
|
144
|
+
var hasOfflineOnly = args.offlineOnly === true;
|
|
145
|
+
var hasColorLabel = typeof args.colorLabel === "number";
|
|
146
|
+
|
|
147
|
+
if (!hasNameContains && !hasExtension && !hasOfflineOnly && !hasColorLabel) {
|
|
148
|
+
return JSON.stringify({ ok: false, error: "at least one filter is required (nameContains, extension, offlineOnly, colorLabel)" });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!app.project) {
|
|
152
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
var filters = {
|
|
156
|
+
nameContains: hasNameContains ? args.nameContains.toLowerCase() : null,
|
|
157
|
+
extension: hasExtension ? ppbSearchItems_normalizeExtFilter(args.extension) : null,
|
|
158
|
+
offlineOnly: hasOfflineOnly,
|
|
159
|
+
colorLabel: hasColorLabel ? args.colorLabel : null
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
var results = [];
|
|
163
|
+
var errorHolder = { error: null };
|
|
164
|
+
var root = app.project.rootItem;
|
|
165
|
+
for (var i = 0; i < root.children.numItems; i++) {
|
|
166
|
+
ppbSearchItems_walk(root.children[i], "", 1, filters, results, errorHolder);
|
|
167
|
+
if (errorHolder.error) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (errorHolder.error) {
|
|
173
|
+
return JSON.stringify({ ok: false, error: errorHolder.error });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return JSON.stringify({ ok: true, result: { items: results, count: results.length } });
|
|
177
|
+
} catch (e) {
|
|
178
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// Command: select-all-clips → ppb_selectAllClips
|
|
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(true, true)) — no QE needed. Ported
|
|
7
|
+
// from leancoderkavy's premiere-pro-mcp `select_all_clips` tool
|
|
8
|
+
// (selection.ts). Mutation — verified via seq.getSelection() afterward.
|
|
9
|
+
|
|
10
|
+
function ppb_selectAllClipsCollectSelection(seq) {
|
|
11
|
+
var sel = null;
|
|
12
|
+
try {
|
|
13
|
+
sel = seq.getSelection();
|
|
14
|
+
} catch (e) {
|
|
15
|
+
sel = null;
|
|
16
|
+
}
|
|
17
|
+
var selCount = 0;
|
|
18
|
+
if (sel) {
|
|
19
|
+
if (typeof sel.numItems === "number") {
|
|
20
|
+
selCount = sel.numItems;
|
|
21
|
+
} else if (typeof sel.length === "number") {
|
|
22
|
+
selCount = sel.length;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var selectedClips = [];
|
|
26
|
+
var cap = selCount > 20 ? 20 : selCount;
|
|
27
|
+
for (var i = 0; i < cap; i++) {
|
|
28
|
+
var item = sel[i];
|
|
29
|
+
var entry = { name: null, mediaType: null, startSeconds: null, endSeconds: null, nodeId: null };
|
|
30
|
+
try { entry.name = item.name; } catch (e) { entry.name = null; }
|
|
31
|
+
try { entry.mediaType = item.mediaType; } catch (e) { entry.mediaType = null; }
|
|
32
|
+
try { entry.startSeconds = timeValueToSeconds(item.start); } catch (e) { entry.startSeconds = null; }
|
|
33
|
+
try { entry.endSeconds = timeValueToSeconds(item.end); } catch (e) { entry.endSeconds = null; }
|
|
34
|
+
try { entry.nodeId = item.nodeId; } catch (e) { entry.nodeId = null; }
|
|
35
|
+
selectedClips.push(entry);
|
|
36
|
+
}
|
|
37
|
+
var result = { selectedCount: selCount, selectedClips: selectedClips };
|
|
38
|
+
if (selCount > 20) {
|
|
39
|
+
result.truncated = true;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function ppb_selectAllClips(argsJson) {
|
|
45
|
+
try {
|
|
46
|
+
var args;
|
|
47
|
+
try {
|
|
48
|
+
args = JSON.parse(argsJson);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var trackType = args.trackType || "both";
|
|
54
|
+
if (trackType !== "video" && trackType !== "audio" && trackType !== "both") {
|
|
55
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\", \"audio\", or \"both\" if given" });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!app.project) {
|
|
59
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var seq = null;
|
|
63
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
64
|
+
seq = findSequenceByName(args.sequenceName);
|
|
65
|
+
if (!seq) {
|
|
66
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
seq = app.project.activeSequence;
|
|
70
|
+
if (!seq) {
|
|
71
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function selectAllInTracks(tracks) {
|
|
76
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
77
|
+
var track = tracks[t];
|
|
78
|
+
for (var c = 0; c < track.clips.numItems; c++) {
|
|
79
|
+
try { track.clips[c].setSelected(true, true); } catch (e) { /* best-effort */ }
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (trackType !== "audio") {
|
|
85
|
+
selectAllInTracks(seq.videoTracks);
|
|
86
|
+
}
|
|
87
|
+
if (trackType !== "video") {
|
|
88
|
+
selectAllInTracks(seq.audioTracks);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
var selectionResult = ppb_selectAllClipsCollectSelection(seq);
|
|
92
|
+
|
|
93
|
+
var result = {
|
|
94
|
+
sequenceName: seq.name,
|
|
95
|
+
trackType: trackType
|
|
96
|
+
};
|
|
97
|
+
result.selectedCount = selectionResult.selectedCount;
|
|
98
|
+
result.selectedClips = selectionResult.selectedClips;
|
|
99
|
+
if (selectionResult.truncated) {
|
|
100
|
+
result.truncated = true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return JSON.stringify({ ok: true, result: result });
|
|
104
|
+
} catch (e) {
|
|
105
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
106
|
+
}
|
|
107
|
+
}
|