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,111 @@
|
|
|
1
|
+
// Command: trim-clip → ppb_trimClip
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// resolveTimelineClip, serializeTrackItem, tryTimeForms, ...) are already
|
|
5
|
+
// defined there.
|
|
6
|
+
//
|
|
7
|
+
// Trims a clip's in and/or out point — SOURCE-MEDIA-RELATIVE seconds, per
|
|
8
|
+
// leancoderkavy's premiere-pro-mcp trim_clip tool and
|
|
9
|
+
// PREMIERE_API_NOTES.md ("assign clip.inPoint/outPoint (Time or ticks
|
|
10
|
+
// string)"). At least one of inPointSeconds/outPointSeconds is required.
|
|
11
|
+
//
|
|
12
|
+
// MUTATION RULE: each requested field is verified via its own read-back
|
|
13
|
+
// after assignment, compared against the request with a tolerance
|
|
14
|
+
// (frame-quantization is expected). A failure on one field does not
|
|
15
|
+
// block attempting the other.
|
|
16
|
+
|
|
17
|
+
function ppb_trimClip(argsJson) {
|
|
18
|
+
try {
|
|
19
|
+
var args;
|
|
20
|
+
try {
|
|
21
|
+
args = JSON.parse(argsJson);
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
27
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
28
|
+
}
|
|
29
|
+
if (typeof args.trackIndex !== "number" || typeof args.clipIndex !== "number") {
|
|
30
|
+
return JSON.stringify({ ok: false, error: "trackIndex and clipIndex are required" });
|
|
31
|
+
}
|
|
32
|
+
var hasIn = typeof args.inPointSeconds === "number";
|
|
33
|
+
var hasOut = typeof args.outPointSeconds === "number";
|
|
34
|
+
if (!hasIn && !hasOut) {
|
|
35
|
+
return JSON.stringify({ ok: false, error: "at least one of inPointSeconds/outPointSeconds is required" });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!app.project) {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var seq = null;
|
|
43
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
44
|
+
seq = findSequenceByName(args.sequenceName);
|
|
45
|
+
if (!seq) {
|
|
46
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
seq = app.project.activeSequence;
|
|
50
|
+
if (!seq) {
|
|
51
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var resolved = resolveTimelineClip(seq, args.trackType, args.trackIndex, args.clipIndex);
|
|
56
|
+
if (resolved.error) {
|
|
57
|
+
return JSON.stringify({ ok: false, error: resolved.error });
|
|
58
|
+
}
|
|
59
|
+
var clip = resolved.clip;
|
|
60
|
+
|
|
61
|
+
var before = serializeTrackItem(clip, args.trackIndex, args.clipIndex);
|
|
62
|
+
var changes = {};
|
|
63
|
+
|
|
64
|
+
if (hasIn) {
|
|
65
|
+
var inAttempt = tryTimeForms(args.inPointSeconds, function (timeArg) {
|
|
66
|
+
clip.inPoint = timeArg;
|
|
67
|
+
});
|
|
68
|
+
var inNewValue = null;
|
|
69
|
+
try { inNewValue = timeValueToSeconds(clip.inPoint); } catch (e2) { inNewValue = null; }
|
|
70
|
+
changes.inPoint = {
|
|
71
|
+
requestedValue: args.inPointSeconds,
|
|
72
|
+
previousValue: before.inPointSeconds,
|
|
73
|
+
newValue: inNewValue,
|
|
74
|
+
verified: inAttempt.success && inNewValue !== null && Math.abs(inNewValue - args.inPointSeconds) <= 0.05,
|
|
75
|
+
attempts: inAttempt.attempts
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (hasOut) {
|
|
80
|
+
var outAttempt = tryTimeForms(args.outPointSeconds, function (timeArg) {
|
|
81
|
+
clip.outPoint = timeArg;
|
|
82
|
+
});
|
|
83
|
+
var outNewValue = null;
|
|
84
|
+
try { outNewValue = timeValueToSeconds(clip.outPoint); } catch (e3) { outNewValue = null; }
|
|
85
|
+
changes.outPoint = {
|
|
86
|
+
requestedValue: args.outPointSeconds,
|
|
87
|
+
previousValue: before.outPointSeconds,
|
|
88
|
+
newValue: outNewValue,
|
|
89
|
+
verified: outAttempt.success && outNewValue !== null && Math.abs(outNewValue - args.outPointSeconds) <= 0.05,
|
|
90
|
+
attempts: outAttempt.attempts
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var after = serializeTrackItem(clip, args.trackIndex, args.clipIndex);
|
|
95
|
+
|
|
96
|
+
return JSON.stringify({
|
|
97
|
+
ok: true,
|
|
98
|
+
result: {
|
|
99
|
+
sequenceName: seq.name,
|
|
100
|
+
trackType: args.trackType,
|
|
101
|
+
trackIndex: args.trackIndex,
|
|
102
|
+
clipIndex: args.clipIndex,
|
|
103
|
+
previousValue: before,
|
|
104
|
+
newValue: after,
|
|
105
|
+
changes: changes
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Command: undo → ppb_undo
|
|
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
|
+
// REWRITTEN 2026-07-17 after the probe session (see BUILD_FINDINGS.md
|
|
7
|
+
// corrections): qe.project.undo() WORKS on this build for operations
|
|
8
|
+
// that enter the undo stack — the earlier "silent no-op" finding was an
|
|
9
|
+
// artifact of testing with marker-add/track-rename, which NEVER enter
|
|
10
|
+
// the stack. qe.project.undoStackIndex() (an int-returning function on
|
|
11
|
+
// this build) is the verification primitive: a real undo decrements it.
|
|
12
|
+
//
|
|
13
|
+
// CAUTION for callers: if YOUR last operation didn't enter the undo
|
|
14
|
+
// stack (markers, track renames, ...), undo() pops whatever IS on top —
|
|
15
|
+
// possibly the user's own last edit. This command therefore refuses to
|
|
16
|
+
// keep looping once the stack index stops moving, and reports the index
|
|
17
|
+
// trajectory so the caller can tell exactly how many stack entries were
|
|
18
|
+
// popped.
|
|
19
|
+
|
|
20
|
+
function ppb_undo(argsJson) {
|
|
21
|
+
try {
|
|
22
|
+
var args;
|
|
23
|
+
try {
|
|
24
|
+
args = JSON.parse(argsJson);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var count = typeof args.count === "number" ? args.count : 1;
|
|
30
|
+
if (isNaN(count) || Math.floor(count) !== count || count < 1) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "count must be a positive integer" });
|
|
32
|
+
}
|
|
33
|
+
var requestedCount = count;
|
|
34
|
+
if (count > 50) {
|
|
35
|
+
count = 50;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!app.project) {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
ensureQEEnabled();
|
|
44
|
+
} catch (e2) {
|
|
45
|
+
return JSON.stringify({ ok: false, error: "app.enableQE() failed: " + e2.toString() });
|
|
46
|
+
}
|
|
47
|
+
if (typeof qe === "undefined" || !qe.project || typeof qe.project.undo !== "function") {
|
|
48
|
+
return JSON.stringify({ ok: false, error: "qe.project.undo is not available on this Premiere build" });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readStackIndex() {
|
|
52
|
+
try {
|
|
53
|
+
if (typeof qe.project.undoStackIndex === "function") {
|
|
54
|
+
return qe.project.undoStackIndex();
|
|
55
|
+
}
|
|
56
|
+
} catch (e) {
|
|
57
|
+
// fall through
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var indexBefore = readStackIndex();
|
|
63
|
+
var undoneCount = 0;
|
|
64
|
+
var stopError = null;
|
|
65
|
+
var stackExhausted = false;
|
|
66
|
+
|
|
67
|
+
for (var i = 0; i < count; i++) {
|
|
68
|
+
var idxPre = readStackIndex();
|
|
69
|
+
try {
|
|
70
|
+
qe.project.undo();
|
|
71
|
+
} catch (e3) {
|
|
72
|
+
stopError = e3.toString();
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
var idxPost = readStackIndex();
|
|
76
|
+
if (idxPre !== null && idxPost !== null) {
|
|
77
|
+
if (idxPost < idxPre) {
|
|
78
|
+
undoneCount++;
|
|
79
|
+
} else {
|
|
80
|
+
// the call no-opped — the stack is exhausted (or this op class
|
|
81
|
+
// isn't undoable); looping further would be pointless
|
|
82
|
+
stackExhausted = true;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
// no index available to verify against — count the non-throwing
|
|
87
|
+
// call, but flag the weaker evidence in the result note
|
|
88
|
+
undoneCount++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
var indexAfter = readStackIndex();
|
|
93
|
+
|
|
94
|
+
return JSON.stringify({
|
|
95
|
+
ok: true,
|
|
96
|
+
result: {
|
|
97
|
+
requestedCount: requestedCount,
|
|
98
|
+
cappedCount: count,
|
|
99
|
+
undoneCount: undoneCount,
|
|
100
|
+
stoppedEarly: undoneCount < count,
|
|
101
|
+
stackExhausted: stackExhausted,
|
|
102
|
+
stopError: stopError,
|
|
103
|
+
method: "qe.project.undo",
|
|
104
|
+
undoStackIndexBefore: indexBefore,
|
|
105
|
+
undoStackIndexAfter: indexAfter,
|
|
106
|
+
note: indexBefore !== null
|
|
107
|
+
? "verified via qe.project.undoStackIndex() — each counted undo decremented the stack index. CAUTION: some operations (markers, track renames) never enter the undo stack; undoing after one of those pops the NEXT stack entry instead."
|
|
108
|
+
: "undoStackIndex() unavailable — undoneCount only reports non-throwing undo calls"
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} catch (e) {
|
|
112
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Command: unlink-selection → ppb_unlinkSelection
|
|
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
|
+
// Unlinks the currently-selected video and audio clips in a sequence.
|
|
7
|
+
// Ported from leancoderkavy's premiere-pro-mcp `unlink_selection` tool
|
|
8
|
+
// (advanced.ts: `seq.unlinkSelection()`) — the standard-DOM counterpart
|
|
9
|
+
// of link-selection.jsx; see that file's header for the full context on
|
|
10
|
+
// why this is standard DOM (not QE, which has no link/unlink at all) and
|
|
11
|
+
// why there's no verified "is linked" state to check. Same before/after
|
|
12
|
+
// selection reporting as link-selection.
|
|
13
|
+
|
|
14
|
+
function ppbUnlinkSelection_collect(seq) {
|
|
15
|
+
var sel = null;
|
|
16
|
+
try {
|
|
17
|
+
sel = seq.getSelection();
|
|
18
|
+
} catch (e) {
|
|
19
|
+
sel = null;
|
|
20
|
+
}
|
|
21
|
+
var selCount = 0;
|
|
22
|
+
if (sel) {
|
|
23
|
+
if (typeof sel.numItems === "number") {
|
|
24
|
+
selCount = sel.numItems;
|
|
25
|
+
} else if (typeof sel.length === "number") {
|
|
26
|
+
selCount = sel.length;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
var items = [];
|
|
30
|
+
var cap = selCount > 20 ? 20 : selCount;
|
|
31
|
+
for (var i = 0; i < cap; i++) {
|
|
32
|
+
var item = sel[i];
|
|
33
|
+
var entry = { name: null, mediaType: null, startSeconds: null, endSeconds: null, nodeId: null };
|
|
34
|
+
try { entry.name = item.name; } catch (e) { entry.name = null; }
|
|
35
|
+
try { entry.mediaType = item.mediaType; } catch (e) { entry.mediaType = null; }
|
|
36
|
+
try { entry.startSeconds = timeValueToSeconds(item.start); } catch (e) { entry.startSeconds = null; }
|
|
37
|
+
try { entry.endSeconds = timeValueToSeconds(item.end); } catch (e) { entry.endSeconds = null; }
|
|
38
|
+
try { entry.nodeId = item.nodeId; } catch (e) { entry.nodeId = null; }
|
|
39
|
+
items.push(entry);
|
|
40
|
+
}
|
|
41
|
+
var out = { selectedCount: selCount, selectedClips: items };
|
|
42
|
+
if (selCount > 20) {
|
|
43
|
+
out.truncated = true;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function ppb_unlinkSelection(argsJson) {
|
|
49
|
+
try {
|
|
50
|
+
var args;
|
|
51
|
+
try {
|
|
52
|
+
args = JSON.parse(argsJson);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!app.project) {
|
|
58
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var seq = null;
|
|
62
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
63
|
+
seq = findSequenceByName(args.sequenceName);
|
|
64
|
+
if (!seq) {
|
|
65
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
seq = app.project.activeSequence;
|
|
69
|
+
if (!seq) {
|
|
70
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (typeof seq.unlinkSelection !== "function") {
|
|
75
|
+
return JSON.stringify({ ok: false, error: "seq.unlinkSelection is not available on this Premiere build" });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var before = ppbUnlinkSelection_collect(seq);
|
|
79
|
+
if (before.selectedCount === 0) {
|
|
80
|
+
return JSON.stringify({
|
|
81
|
+
ok: false,
|
|
82
|
+
error: "nothing is selected in sequence \"" + seq.name + "\" — select the linked clip(s) to unlink first (e.g. via set-clip-selection)"
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
seq.unlinkSelection();
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return JSON.stringify({ ok: false, error: "seq.unlinkSelection() failed: " + e.toString() });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
var after = ppbUnlinkSelection_collect(seq);
|
|
93
|
+
|
|
94
|
+
return JSON.stringify({
|
|
95
|
+
ok: true,
|
|
96
|
+
result: {
|
|
97
|
+
sequenceName: seq.name,
|
|
98
|
+
before: before,
|
|
99
|
+
after: after,
|
|
100
|
+
note: "there is no confirmed 'is linked' read-back API (PREMIERE_API_NOTES.md) — before/after selection is reported as the only available signal; the call not throwing is the closest thing to success confirmation here."
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
} catch (e) {
|
|
104
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
// Command: unnest-sequence → ppb_unnestSequence
|
|
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 sequence.ts
|
|
7
|
+
// unnest_sequence — a real (non-stub) implementation, so this is a full
|
|
8
|
+
// port rather than a skip. Replaces a nested-sequence clip on the
|
|
9
|
+
// timeline with copies of the nested sequence's own clips, addressed by
|
|
10
|
+
// the outer clip's nodeId (not trackType/trackIndex/clipIndex, since the
|
|
11
|
+
// nested clip could be on either track type and the reference itself
|
|
12
|
+
// only ever addresses it by nodeId).
|
|
13
|
+
//
|
|
14
|
+
// Algorithm (matches the reference): find the timeline clip by nodeId,
|
|
15
|
+
// confirm its projectItem resolves to another open sequence (nodeId/name
|
|
16
|
+
// matched against app.project.sequences — the "is this a nested sequence
|
|
17
|
+
// clip" test), remove the nested-sequence clip, then re-insert each of
|
|
18
|
+
// the nested sequence's own clips at an offset position (outer clip's own
|
|
19
|
+
// start + the nested clip's own start) on the corresponding track.
|
|
20
|
+
//
|
|
21
|
+
// Semi-destructive/structural: removes the nested-sequence clip outright
|
|
22
|
+
// before re-inserting its contents — if insertion partway fails, the
|
|
23
|
+
// timeline is left in a partially-unnested state (documented in the
|
|
24
|
+
// result, not silently swallowed). Undo is non-functional on this build.
|
|
25
|
+
//
|
|
26
|
+
// Verification: reports the outer clip removal AND, per re-inserted
|
|
27
|
+
// clip, whether seq.insertClip() was reached without throwing — plus a
|
|
28
|
+
// final total-clip-count comparison across the whole sequence (never
|
|
29
|
+
// trusting insertClip()'s own return value).
|
|
30
|
+
function ppb_findTimelineClipByNodeId(seq, nodeId) {
|
|
31
|
+
function scan(tracks, trackType) {
|
|
32
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
33
|
+
for (var c = 0; c < tracks[t].clips.numItems; c++) {
|
|
34
|
+
var clip = tracks[t].clips[c];
|
|
35
|
+
var id = null;
|
|
36
|
+
try { id = clip.nodeId; } catch (e) { id = null; }
|
|
37
|
+
if (id === nodeId) {
|
|
38
|
+
return { clip: clip, trackType: trackType, trackIndex: t, clipIndex: c };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return scan(seq.videoTracks, "video") || scan(seq.audioTracks, "audio");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function ppb_countAllClipsUnnestSequence(seq) {
|
|
48
|
+
var total = 0;
|
|
49
|
+
try {
|
|
50
|
+
for (var v = 0; v < seq.videoTracks.numTracks; v++) {
|
|
51
|
+
total += seq.videoTracks[v].clips.numItems;
|
|
52
|
+
}
|
|
53
|
+
} catch (e) {
|
|
54
|
+
// best-effort
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
for (var a = 0; a < seq.audioTracks.numTracks; a++) {
|
|
58
|
+
total += seq.audioTracks[a].clips.numItems;
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
// best-effort
|
|
62
|
+
}
|
|
63
|
+
return total;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function ppb_unnestSequence(argsJson) {
|
|
67
|
+
try {
|
|
68
|
+
var args;
|
|
69
|
+
try {
|
|
70
|
+
args = JSON.parse(argsJson);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!args.nodeId || typeof args.nodeId !== "string") {
|
|
76
|
+
return JSON.stringify({ ok: false, error: "nodeId is required (node ID of the nested-sequence clip on the timeline)" });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!app.project) {
|
|
80
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var seq = null;
|
|
84
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
85
|
+
seq = findSequenceByName(args.sequenceName);
|
|
86
|
+
if (!seq) {
|
|
87
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
seq = app.project.activeSequence;
|
|
91
|
+
if (!seq) {
|
|
92
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
var found = ppb_findTimelineClipByNodeId(seq, args.nodeId);
|
|
97
|
+
if (!found) {
|
|
98
|
+
return JSON.stringify({ ok: false, error: "no clip with nodeId \"" + args.nodeId + "\" found on sequence \"" + seq.name + "\"" });
|
|
99
|
+
}
|
|
100
|
+
var clip = found.clip;
|
|
101
|
+
var clipName = null;
|
|
102
|
+
try { clipName = clip.name; } catch (e) { clipName = null; }
|
|
103
|
+
|
|
104
|
+
var projectItem = null;
|
|
105
|
+
try { projectItem = clip.projectItem; } catch (e) { projectItem = null; }
|
|
106
|
+
if (!projectItem) {
|
|
107
|
+
return JSON.stringify({ ok: false, error: "clip \"" + clipName + "\" has no projectItem — cannot resolve it to a nested sequence" });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
var nestedSeq = null;
|
|
111
|
+
for (var i = 0; i < app.project.sequences.numSequences; i++) {
|
|
112
|
+
var s = app.project.sequences[i];
|
|
113
|
+
var sName = null;
|
|
114
|
+
try { sName = s.name; } catch (e) { sName = null; }
|
|
115
|
+
var sId = null;
|
|
116
|
+
try { sId = s.sequenceID; } catch (e) { sId = null; }
|
|
117
|
+
var itName = null;
|
|
118
|
+
try { itName = projectItem.name; } catch (e) { itName = null; }
|
|
119
|
+
var itNodeId = null;
|
|
120
|
+
try { itNodeId = projectItem.nodeId; } catch (e) { itNodeId = null; }
|
|
121
|
+
if (sName === itName || sId === itNodeId) {
|
|
122
|
+
nestedSeq = s;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!nestedSeq) {
|
|
127
|
+
return JSON.stringify({ ok: false, error: "clip \"" + clipName + "\" is not a nested sequence (its projectItem doesn't match any open sequence)" });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
var startTicks = null;
|
|
131
|
+
try { startTicks = clip.start.ticks; } catch (e) { startTicks = null; }
|
|
132
|
+
if (startTicks === null) {
|
|
133
|
+
return JSON.stringify({ ok: false, error: "could not read the nested clip's own start time" });
|
|
134
|
+
}
|
|
135
|
+
var trackIndex = found.trackIndex;
|
|
136
|
+
var trackType = found.trackType;
|
|
137
|
+
|
|
138
|
+
var countBefore = ppb_countAllClipsUnnestSequence(seq);
|
|
139
|
+
|
|
140
|
+
var removeError = null;
|
|
141
|
+
try {
|
|
142
|
+
clip.remove(false, false);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
removeError = e.toString();
|
|
145
|
+
}
|
|
146
|
+
if (removeError !== null) {
|
|
147
|
+
return JSON.stringify({ ok: false, error: "failed to remove the nested-sequence clip: " + removeError });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
var addedClips = [];
|
|
151
|
+
var insertErrors = [];
|
|
152
|
+
var tracks = trackType === "video" ? nestedSeq.videoTracks : nestedSeq.audioTracks;
|
|
153
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
154
|
+
var track = tracks[t];
|
|
155
|
+
for (var c = 0; c < track.clips.numItems; c++) {
|
|
156
|
+
var nestedClip = track.clips[c];
|
|
157
|
+
var nestedProjectItem = null;
|
|
158
|
+
try { nestedProjectItem = nestedClip.projectItem; } catch (e) { nestedProjectItem = null; }
|
|
159
|
+
if (!nestedProjectItem) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
var nestedName = null;
|
|
163
|
+
try { nestedName = nestedClip.name; } catch (e) { nestedName = null; }
|
|
164
|
+
|
|
165
|
+
var insertTime = null;
|
|
166
|
+
try {
|
|
167
|
+
insertTime = (parseFloat(startTicks) + parseFloat(nestedClip.start.ticks)).toString();
|
|
168
|
+
} catch (e) {
|
|
169
|
+
insertErrors.push({ clip: nestedName, error: "could not compute insert time: " + e.toString() });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
var targetTrack = trackIndex + t;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
if (trackType === "video") {
|
|
176
|
+
seq.insertClip(nestedProjectItem, insertTime, targetTrack, targetTrack);
|
|
177
|
+
} else {
|
|
178
|
+
seq.insertClip(nestedProjectItem, insertTime, 0, targetTrack);
|
|
179
|
+
}
|
|
180
|
+
addedClips.push(nestedName);
|
|
181
|
+
} catch (e2) {
|
|
182
|
+
insertErrors.push({ clip: nestedName, error: e2.toString() });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
var countAfter = ppb_countAllClipsUnnestSequence(seq);
|
|
188
|
+
|
|
189
|
+
return JSON.stringify({
|
|
190
|
+
ok: insertErrors.length === 0,
|
|
191
|
+
result: {
|
|
192
|
+
sequenceName: seq.name,
|
|
193
|
+
unnestedClipName: clipName,
|
|
194
|
+
nestedSequenceName: nestedSeq.name,
|
|
195
|
+
trackType: trackType,
|
|
196
|
+
trackIndex: trackIndex,
|
|
197
|
+
addedClips: addedClips,
|
|
198
|
+
addedCount: addedClips.length,
|
|
199
|
+
insertErrors: insertErrors,
|
|
200
|
+
countBefore: countBefore,
|
|
201
|
+
countAfter: countAfter
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
} catch (e) {
|
|
205
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Command: update-marker → ppb_updateMarker
|
|
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 update_marker tool, but
|
|
7
|
+
// re-addressed: the reference identifies the target marker by matching
|
|
8
|
+
// its start time within a tolerance window; this panel instead identifies
|
|
9
|
+
// it by .guid (the same stable identity list-markers/get-clip-markers
|
|
10
|
+
// already expose), which is unambiguous and avoids float-time matching
|
|
11
|
+
// entirely. Only name/comments/type/colorIndex/endSeconds/durationSeconds
|
|
12
|
+
// are mutable here — marker.start itself is not attempted (no confirmed
|
|
13
|
+
// write API for it; see PREMIERE_API_NOTES.md's markers section).
|
|
14
|
+
//
|
|
15
|
+
// MUTATION RULE: after applying changes, the marker is re-found by the
|
|
16
|
+
// same guid via a fresh getFirstMarker()/getNextMarker() walk and
|
|
17
|
+
// re-serialized from that live object — never returned from the
|
|
18
|
+
// reference held before mutating.
|
|
19
|
+
|
|
20
|
+
function ppbUpdateMarker_serializeOne(m) {
|
|
21
|
+
var entry = { name: null, comments: null, type: null, startSeconds: null, endSeconds: null, guid: null };
|
|
22
|
+
try { entry.name = m.name; } catch (e) { entry.name = null; }
|
|
23
|
+
try { entry.comments = m.comments; } catch (e) { entry.comments = null; }
|
|
24
|
+
try { entry.type = m.type; } catch (e) { entry.type = null; }
|
|
25
|
+
try { entry.startSeconds = timeValueToSeconds(m.start); } catch (e) { entry.startSeconds = null; }
|
|
26
|
+
try { entry.endSeconds = timeValueToSeconds(m.end); } catch (e) { entry.endSeconds = null; }
|
|
27
|
+
try { entry.guid = m.guid; } catch (e) { entry.guid = null; }
|
|
28
|
+
return entry;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ppbUpdateMarker_findByGuid(seq, guid) {
|
|
32
|
+
var m = seq.markers.getFirstMarker();
|
|
33
|
+
var iterations = 0;
|
|
34
|
+
while (m !== null && typeof m !== "undefined" && iterations < 10000) {
|
|
35
|
+
var thisGuid = null;
|
|
36
|
+
try { thisGuid = m.guid; } catch (e) { thisGuid = null; }
|
|
37
|
+
if (thisGuid === guid) {
|
|
38
|
+
return m;
|
|
39
|
+
}
|
|
40
|
+
m = seq.markers.getNextMarker(m);
|
|
41
|
+
iterations++;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function ppb_updateMarker(argsJson) {
|
|
47
|
+
try {
|
|
48
|
+
var args;
|
|
49
|
+
try {
|
|
50
|
+
args = JSON.parse(argsJson);
|
|
51
|
+
} catch (e) {
|
|
52
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (typeof args.guid !== "string" || args.guid.length === 0) {
|
|
56
|
+
return JSON.stringify({ ok: false, error: "guid is required" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!app.project) {
|
|
60
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var seq = null;
|
|
64
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
65
|
+
seq = findSequenceByName(args.sequenceName);
|
|
66
|
+
if (!seq) {
|
|
67
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
seq = app.project.activeSequence;
|
|
71
|
+
if (!seq) {
|
|
72
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var marker = ppbUpdateMarker_findByGuid(seq, args.guid);
|
|
77
|
+
if (!marker) {
|
|
78
|
+
return JSON.stringify({ ok: false, error: "no marker found with guid \"" + args.guid + "\" on this sequence" });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
var applied = {};
|
|
82
|
+
if (typeof args.name === "string") {
|
|
83
|
+
try { marker.name = args.name; applied.name = true; } catch (e) { applied.name = false; }
|
|
84
|
+
}
|
|
85
|
+
if (typeof args.comments === "string") {
|
|
86
|
+
try { marker.comments = args.comments; applied.comments = true; } catch (e) { applied.comments = false; }
|
|
87
|
+
}
|
|
88
|
+
if (typeof args.type === "string") {
|
|
89
|
+
try { marker.type = args.type; applied.type = true; } catch (e) { applied.type = false; }
|
|
90
|
+
}
|
|
91
|
+
if (typeof args.colorIndex === "number") {
|
|
92
|
+
try { marker.setColorByIndex(args.colorIndex); applied.colorIndex = true; } catch (e) { applied.colorIndex = false; }
|
|
93
|
+
}
|
|
94
|
+
if (typeof args.durationSeconds === "number") {
|
|
95
|
+
try {
|
|
96
|
+
var startSeconds = timeValueToSeconds(marker.start);
|
|
97
|
+
marker.end = startSeconds + args.durationSeconds;
|
|
98
|
+
applied.durationSeconds = true;
|
|
99
|
+
} catch (e) { applied.durationSeconds = false; }
|
|
100
|
+
} else if (typeof args.endSeconds === "number") {
|
|
101
|
+
try { marker.end = args.endSeconds; applied.endSeconds = true; } catch (e) { applied.endSeconds = false; }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
var reFound = ppbUpdateMarker_findByGuid(seq, args.guid);
|
|
105
|
+
if (!reFound) {
|
|
106
|
+
return JSON.stringify({ ok: false, error: "marker vanished after update (re-find by guid failed)", applied: applied });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return JSON.stringify({
|
|
110
|
+
ok: true,
|
|
111
|
+
result: {
|
|
112
|
+
sequenceName: seq.name,
|
|
113
|
+
applied: applied,
|
|
114
|
+
marker: ppbUpdateMarker_serializeOne(reFound)
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
119
|
+
}
|
|
120
|
+
}
|