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,217 @@
|
|
|
1
|
+
// Command: import-media → ppb_importMedia
|
|
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 import_media tool. Per
|
|
7
|
+
// PREMIERE_API_NOTES.md's "Project / bins / import" section:
|
|
8
|
+
// app.project.importFiles()'s own return value is unreliable, and an
|
|
9
|
+
// unsupported/unrecognized file extension can pop a BLOCKING modal dialog
|
|
10
|
+
// that freezes the whole CEP bridge — so files are pre-filtered against a
|
|
11
|
+
// safe extension allowlist below, and success is verified by diffing
|
|
12
|
+
// nodeId snapshots of the whole project tree before/after the import call,
|
|
13
|
+
// never by trusting importFiles()'s return value. Helper names are
|
|
14
|
+
// prefixed ppbImportMedia_ to avoid colliding with same-purpose helpers in
|
|
15
|
+
// other lazily-loaded command files evaluated into this same global
|
|
16
|
+
// context (import-folder.jsx and import-image-sequence.jsx duplicate this
|
|
17
|
+
// allowlist/snapshot logic under their own prefixes for the same reason).
|
|
18
|
+
|
|
19
|
+
var PPB_IMPORT_MEDIA_ALLOWED_EXTENSIONS = [
|
|
20
|
+
// video
|
|
21
|
+
"mp4", "mov", "avi", "mkv", "webm", "mxf", "m4v", "wmv", "mpg", "mpeg",
|
|
22
|
+
// audio
|
|
23
|
+
"wav", "mp3", "aac", "m4a", "aif", "aiff", "flac", "ogg",
|
|
24
|
+
// image
|
|
25
|
+
"png", "jpg", "jpeg", "gif", "tiff", "tif", "bmp", "psd", "tga", "exr", "dpx", "webp",
|
|
26
|
+
// project
|
|
27
|
+
"prproj"
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function ppbImportMedia_extensionOf(path) {
|
|
31
|
+
var lastDot = path.lastIndexOf(".");
|
|
32
|
+
if (lastDot === -1 || lastDot === path.length - 1) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
return path.substring(lastDot + 1).toLowerCase();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function ppbImportMedia_isAllowedExtension(path) {
|
|
39
|
+
var ext = ppbImportMedia_extensionOf(path);
|
|
40
|
+
for (var i = 0; i < PPB_IMPORT_MEDIA_ALLOWED_EXTENSIONS.length; i++) {
|
|
41
|
+
if (ext === PPB_IMPORT_MEDIA_ALLOWED_EXTENSIONS[i]) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Depth-capped (32) recursive walk collecting every nodeId currently in the
|
|
49
|
+
// project, keyed in a plain object for O(1) diffing. Recurses on
|
|
50
|
+
// children-presence (item.children truthy), NOT an isBin() gate — the
|
|
51
|
+
// ROOT item's type is ROOT, not BIN, and per get-project-item-info.jsx's
|
|
52
|
+
// live-debugged finding, an isBin() gate here would silently stop any
|
|
53
|
+
// walk that starts at the root itself. Snapshot walks in this file always
|
|
54
|
+
// start at rootItem.children, but the same helper is reused by the
|
|
55
|
+
// resolveBinPath below which DOES start at rootItem, so the non-gated
|
|
56
|
+
// form is used uniformly.
|
|
57
|
+
function ppbImportMedia_snapshotNodeIds(item, depth, seen) {
|
|
58
|
+
if (depth > 32) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
if (item.nodeId) {
|
|
63
|
+
seen[item.nodeId] = true;
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {
|
|
66
|
+
// ignore
|
|
67
|
+
}
|
|
68
|
+
if (item.children && item.children.numItems > 0) {
|
|
69
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
70
|
+
ppbImportMedia_snapshotNodeIds(item.children[i], depth + 1, seen);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function ppbImportMedia_takeSnapshot() {
|
|
76
|
+
var seen = {};
|
|
77
|
+
var root = app.project.rootItem;
|
|
78
|
+
ppbImportMedia_snapshotNodeIds(root, 0, seen);
|
|
79
|
+
return seen;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Finds every item in the current project whose nodeId isn't in
|
|
83
|
+
// `beforeSnapshot` — the newly-imported items. Depth-capped the same way.
|
|
84
|
+
function ppbImportMedia_collectNew(item, depth, beforeSnapshot, out) {
|
|
85
|
+
if (depth > 32) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
if (item.nodeId && !beforeSnapshot[item.nodeId]) {
|
|
90
|
+
var entry = { name: null, nodeId: null, treePath: null, mediaPath: null };
|
|
91
|
+
try { entry.name = item.name; } catch (e) { entry.name = null; }
|
|
92
|
+
try { entry.nodeId = item.nodeId; } catch (e) { entry.nodeId = null; }
|
|
93
|
+
try { entry.treePath = item.treePath; } catch (e) { entry.treePath = null; }
|
|
94
|
+
try { entry.mediaPath = item.getMediaPath(); } catch (e) { entry.mediaPath = null; }
|
|
95
|
+
out.push(entry);
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
// ignore
|
|
99
|
+
}
|
|
100
|
+
if (item.children && item.children.numItems > 0) {
|
|
101
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
102
|
+
ppbImportMedia_collectNew(item.children[i], depth + 1, beforeSnapshot, out);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Resolves (but does NOT create) a '/'-separated bin path against the
|
|
108
|
+
// project's root bin. Returns {bin} on success or {error} if any segment
|
|
109
|
+
// is missing.
|
|
110
|
+
function ppbImportMedia_resolveBinPath(binPath) {
|
|
111
|
+
var segments = binPath.split("/").filter(function (s) { return s.length > 0; });
|
|
112
|
+
var current = app.project.rootItem;
|
|
113
|
+
for (var i = 0; i < segments.length; i++) {
|
|
114
|
+
var found = null;
|
|
115
|
+
for (var j = 0; j < current.children.numItems; j++) {
|
|
116
|
+
var child = current.children[j];
|
|
117
|
+
if (child.name === segments[i] && typeof ProjectItemType !== "undefined" && child.type === ProjectItemType.BIN) {
|
|
118
|
+
found = child;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!found) {
|
|
123
|
+
return { error: "bin path segment \"" + segments[i] + "\" not found in \"" + binPath + "\" (target bin must already exist)" };
|
|
124
|
+
}
|
|
125
|
+
current = found;
|
|
126
|
+
}
|
|
127
|
+
return { bin: current };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function ppb_importMedia(argsJson) {
|
|
131
|
+
try {
|
|
132
|
+
var args;
|
|
133
|
+
try {
|
|
134
|
+
args = JSON.parse(argsJson);
|
|
135
|
+
} catch (e) {
|
|
136
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
var filePaths = null;
|
|
140
|
+
if (typeof args.filePaths === "string" && args.filePaths.length > 0) {
|
|
141
|
+
try {
|
|
142
|
+
filePaths = JSON.parse(args.filePaths);
|
|
143
|
+
} catch (e) {
|
|
144
|
+
return JSON.stringify({ ok: false, error: "filePaths must be a JSON array string: " + e.toString() });
|
|
145
|
+
}
|
|
146
|
+
} else if (args.filePaths instanceof Array) {
|
|
147
|
+
filePaths = args.filePaths;
|
|
148
|
+
} else if (typeof args.filePath === "string" && args.filePath.length > 0) {
|
|
149
|
+
filePaths = [args.filePath];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!filePaths || !(filePaths instanceof Array) || filePaths.length === 0) {
|
|
153
|
+
return JSON.stringify({ ok: false, error: "either filePath (string) or filePaths (JSON array) is required" });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!app.project) {
|
|
157
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
var refused = [];
|
|
161
|
+
for (var i = 0; i < filePaths.length; i++) {
|
|
162
|
+
if (!ppbImportMedia_isAllowedExtension(filePaths[i])) {
|
|
163
|
+
refused.push(filePaths[i]);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (refused.length > 0) {
|
|
167
|
+
return JSON.stringify({
|
|
168
|
+
ok: false,
|
|
169
|
+
error: "refusing to import file(s) with an unrecognized extension — an unsupported format can pop a " +
|
|
170
|
+
"BLOCKING dialog that freezes the Premiere Bridge panel: " + refused.join(", "),
|
|
171
|
+
refused: refused,
|
|
172
|
+
allowedExtensions: PPB_IMPORT_MEDIA_ALLOWED_EXTENSIONS
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
var targetBin = app.project.rootItem;
|
|
177
|
+
if (typeof args.targetBinPath === "string" && args.targetBinPath.length > 0) {
|
|
178
|
+
var resolved = ppbImportMedia_resolveBinPath(args.targetBinPath);
|
|
179
|
+
if (resolved.error) {
|
|
180
|
+
return JSON.stringify({ ok: false, error: resolved.error });
|
|
181
|
+
}
|
|
182
|
+
targetBin = resolved.bin;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
var before = ppbImportMedia_takeSnapshot();
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
app.project.importFiles(filePaths, true, targetBin, false);
|
|
189
|
+
} catch (e) {
|
|
190
|
+
return JSON.stringify({ ok: false, error: "app.project.importFiles() threw: " + e.toString() });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var imported = [];
|
|
194
|
+
ppbImportMedia_collectNew(app.project.rootItem, 0, before, imported);
|
|
195
|
+
|
|
196
|
+
if (imported.length === 0) {
|
|
197
|
+
return JSON.stringify({
|
|
198
|
+
ok: false,
|
|
199
|
+
error: "importFiles() did not throw, but no new project item appeared (nodeId-diff found nothing) — " +
|
|
200
|
+
"the file(s) may already be in the project, or the import silently failed",
|
|
201
|
+
requestedFiles: filePaths
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return JSON.stringify({
|
|
206
|
+
ok: true,
|
|
207
|
+
result: {
|
|
208
|
+
requestedFiles: filePaths,
|
|
209
|
+
targetBinPath: args.targetBinPath || null,
|
|
210
|
+
importedCount: imported.length,
|
|
211
|
+
imported: imported
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
} catch (e) {
|
|
215
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Command: import-mogrt-from-library → ppb_importMogrtFromLibrary
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — findSequenceByName,
|
|
4
|
+
// secondsToTicksString are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ported from leancoderkavy's premiere-pro-mcp text.ts
|
|
7
|
+
// import_mogrt_from_library, WITH ONE DELIBERATE CORRECTION: that
|
|
8
|
+
// reference tool calls seq.importMGTFromLibrary(mogrtName, startTicks,
|
|
9
|
+
// trackIndex, trackIndex) — omitting a library name entirely — but
|
|
10
|
+
// PREMIERE_API_NOTES.md documents the real signature as
|
|
11
|
+
// seq.importMGTFromLibrary(libName, mogrtName, ticks, v, a), five
|
|
12
|
+
// arguments with the library name first. The reference's own call would
|
|
13
|
+
// pass a mogrt name where the library name belongs, which reads like a
|
|
14
|
+
// bug in that repo rather than an intentional simplification — this port
|
|
15
|
+
// follows PREMIERE_API_NOTES.md's documented signature instead, adding a
|
|
16
|
+
// required libraryName argument the reference's own tool lacks.
|
|
17
|
+
//
|
|
18
|
+
// MUTATION RULE: same as import-mogrt — verified via the target video
|
|
19
|
+
// track's own clip count before/after, never the call's return value
|
|
20
|
+
// (same ambiguous-return-type caveat).
|
|
21
|
+
function ppb_importMogrtFromLibrary(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 (typeof args.libraryName !== "string" || !args.libraryName) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "libraryName is required (PREMIERE_API_NOTES.md documents importMGTFromLibrary as (libName, mogrtName, ticks, v, a) — the reference tool this ports omits it, which this command does not follow)" });
|
|
32
|
+
}
|
|
33
|
+
if (typeof args.mogrtName !== "string" || !args.mogrtName) {
|
|
34
|
+
return JSON.stringify({ ok: false, error: "mogrtName is required" });
|
|
35
|
+
}
|
|
36
|
+
if (typeof args.startSeconds !== "number") {
|
|
37
|
+
return JSON.stringify({ ok: false, error: "startSeconds is required" });
|
|
38
|
+
}
|
|
39
|
+
if (typeof args.videoTrackIndex !== "number") {
|
|
40
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndex is required" });
|
|
41
|
+
}
|
|
42
|
+
if (typeof args.audioTrackIndex !== "number") {
|
|
43
|
+
return JSON.stringify({ ok: false, error: "audioTrackIndex is required" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!app.project) {
|
|
47
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
var seq = null;
|
|
51
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
52
|
+
seq = findSequenceByName(args.sequenceName);
|
|
53
|
+
if (!seq) {
|
|
54
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
seq = app.project.activeSequence;
|
|
58
|
+
if (!seq) {
|
|
59
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
var numVideoTracks;
|
|
64
|
+
try { numVideoTracks = seq.videoTracks.numTracks; } catch (e2) { numVideoTracks = 0; }
|
|
65
|
+
if (args.videoTrackIndex >= numVideoTracks) {
|
|
66
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndex " + args.videoTrackIndex + " is out of range — sequence has " + numVideoTracks + " video track(s)" });
|
|
67
|
+
}
|
|
68
|
+
var videoTrack = seq.videoTracks[args.videoTrackIndex];
|
|
69
|
+
var trackClipCountBefore = null;
|
|
70
|
+
try { trackClipCountBefore = videoTrack.clips.numItems; } catch (e3) { trackClipCountBefore = null; }
|
|
71
|
+
|
|
72
|
+
var startTicks = secondsToTicksString(args.startSeconds);
|
|
73
|
+
var importResult = null;
|
|
74
|
+
try {
|
|
75
|
+
importResult = seq.importMGTFromLibrary(args.libraryName, args.mogrtName, startTicks, args.videoTrackIndex, args.audioTrackIndex);
|
|
76
|
+
} catch (e4) {
|
|
77
|
+
return JSON.stringify({ ok: false, error: "seq.importMGTFromLibrary() failed: " + e4.toString() });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var trackClipCountAfter = null;
|
|
81
|
+
try { trackClipCountAfter = videoTrack.clips.numItems; } catch (e5) { trackClipCountAfter = null; }
|
|
82
|
+
|
|
83
|
+
var placed = trackClipCountBefore !== null && trackClipCountAfter !== null && trackClipCountAfter > trackClipCountBefore;
|
|
84
|
+
|
|
85
|
+
return JSON.stringify({
|
|
86
|
+
ok: true,
|
|
87
|
+
result: {
|
|
88
|
+
sequenceName: seq.name,
|
|
89
|
+
libraryName: args.libraryName,
|
|
90
|
+
mogrtName: args.mogrtName,
|
|
91
|
+
startSeconds: args.startSeconds,
|
|
92
|
+
videoTrackIndex: args.videoTrackIndex,
|
|
93
|
+
audioTrackIndex: args.audioTrackIndex,
|
|
94
|
+
trackClipCountBefore: trackClipCountBefore,
|
|
95
|
+
trackClipCountAfter: trackClipCountAfter,
|
|
96
|
+
placed: placed,
|
|
97
|
+
verified: placed,
|
|
98
|
+
importReturnValueTruthy: !!importResult,
|
|
99
|
+
note: "libraryName argument added per PREMIERE_API_NOTES.md's documented 5-arg signature — the ported reference tool's own call omits it (see file header comment)."
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
} catch (e) {
|
|
103
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Command: import-mogrt → ppb_importMogrt
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — findSequenceByName,
|
|
4
|
+
// secondsToTicksString, timeValueToSeconds are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ported from leancoderkavy's premiere-pro-mcp text.ts import_mogrt.
|
|
7
|
+
// Imports a .mogrt file directly onto the timeline via
|
|
8
|
+
// seq.importMGT(mogrtPath, startTicksString, videoTrackIndex,
|
|
9
|
+
// audioTrackIndex).
|
|
10
|
+
//
|
|
11
|
+
// ⚠️ RETURN-VALUE DISCREPANCY: text.ts treats importMGT()'s return value
|
|
12
|
+
// as a boolean ("if (!success) return __error(...)"), but
|
|
13
|
+
// PREMIERE_API_NOTES.md documents it as returning a trackItem object
|
|
14
|
+
// ("seq.importMGT(...) → trackItem"). Both are handled defensively here —
|
|
15
|
+
// the raw return value's type is reported, and if it looks like a
|
|
16
|
+
// trackItem (a non-null object with a readable .name), that's surfaced
|
|
17
|
+
// too — but the PRIMARY verification is independent of either claim: the
|
|
18
|
+
// target video track's own clip count before/after, same MUTATION RULE
|
|
19
|
+
// every other placement command in this panel follows (add-to-timeline,
|
|
20
|
+
// duplicate-clip, ...) rather than trusting an ambiguous return value.
|
|
21
|
+
function ppb_importMogrt(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 (typeof args.mogrtPath !== "string" || !args.mogrtPath) {
|
|
31
|
+
return JSON.stringify({ ok: false, error: "mogrtPath is required" });
|
|
32
|
+
}
|
|
33
|
+
if (typeof args.startSeconds !== "number") {
|
|
34
|
+
return JSON.stringify({ ok: false, error: "startSeconds is required" });
|
|
35
|
+
}
|
|
36
|
+
if (typeof args.videoTrackIndex !== "number") {
|
|
37
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndex is required" });
|
|
38
|
+
}
|
|
39
|
+
if (typeof args.audioTrackIndex !== "number") {
|
|
40
|
+
return JSON.stringify({ ok: false, error: "audioTrackIndex is required" });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!app.project) {
|
|
44
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var seq = null;
|
|
48
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
49
|
+
seq = findSequenceByName(args.sequenceName);
|
|
50
|
+
if (!seq) {
|
|
51
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
seq = app.project.activeSequence;
|
|
55
|
+
if (!seq) {
|
|
56
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var numVideoTracks;
|
|
61
|
+
try { numVideoTracks = seq.videoTracks.numTracks; } catch (e2) { numVideoTracks = 0; }
|
|
62
|
+
if (args.videoTrackIndex >= numVideoTracks) {
|
|
63
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndex " + args.videoTrackIndex + " is out of range — sequence has " + numVideoTracks + " video track(s)" });
|
|
64
|
+
}
|
|
65
|
+
var videoTrack = seq.videoTracks[args.videoTrackIndex];
|
|
66
|
+
var trackClipCountBefore = null;
|
|
67
|
+
try { trackClipCountBefore = videoTrack.clips.numItems; } catch (e3) { trackClipCountBefore = null; }
|
|
68
|
+
|
|
69
|
+
var startTicks = secondsToTicksString(args.startSeconds);
|
|
70
|
+
var importResult = null;
|
|
71
|
+
try {
|
|
72
|
+
importResult = seq.importMGT(args.mogrtPath, startTicks, args.videoTrackIndex, args.audioTrackIndex);
|
|
73
|
+
} catch (e4) {
|
|
74
|
+
return JSON.stringify({ ok: false, error: "seq.importMGT() failed: " + e4.toString() });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var trackClipCountAfter = null;
|
|
78
|
+
try { trackClipCountAfter = videoTrack.clips.numItems; } catch (e5) { trackClipCountAfter = null; }
|
|
79
|
+
|
|
80
|
+
var placed = trackClipCountBefore !== null && trackClipCountAfter !== null && trackClipCountAfter > trackClipCountBefore;
|
|
81
|
+
|
|
82
|
+
var returnValueType = typeof importResult;
|
|
83
|
+
var returnValueIsObject = importResult !== null && typeof importResult === "object";
|
|
84
|
+
var returnValueName = null;
|
|
85
|
+
if (returnValueIsObject) {
|
|
86
|
+
try { returnValueName = importResult.name; } catch (e6) { returnValueName = null; }
|
|
87
|
+
}
|
|
88
|
+
var returnValueTruthy = !!importResult;
|
|
89
|
+
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
ok: true,
|
|
92
|
+
result: {
|
|
93
|
+
sequenceName: seq.name,
|
|
94
|
+
mogrtPath: args.mogrtPath,
|
|
95
|
+
startSeconds: args.startSeconds,
|
|
96
|
+
videoTrackIndex: args.videoTrackIndex,
|
|
97
|
+
audioTrackIndex: args.audioTrackIndex,
|
|
98
|
+
trackClipCountBefore: trackClipCountBefore,
|
|
99
|
+
trackClipCountAfter: trackClipCountAfter,
|
|
100
|
+
placed: placed,
|
|
101
|
+
verified: placed,
|
|
102
|
+
importReturnValueType: returnValueType,
|
|
103
|
+
importReturnValueTruthy: returnValueTruthy,
|
|
104
|
+
importReturnValueName: returnValueName,
|
|
105
|
+
note: "verified via the target video track's clip count, not importMGT()'s own return value — text.ts treats that return as a boolean while PREMIERE_API_NOTES.md documents it as a trackItem; both are reported above but neither is trusted for verification."
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Command: import-sequences-from-project → ppb_importSequencesFromProject
|
|
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
|
|
6
|
+
// import_sequences. Calls app.project.importSequences(prprojPath,
|
|
7
|
+
// [seqIds]) per PREMIERE_API_NOTES.md's Sequences table; if sequenceIds
|
|
8
|
+
// is omitted, calls the one-arg form (documented by the reference tool
|
|
9
|
+
// as "imports all sequences"). File-exists check on projectPath first,
|
|
10
|
+
// same cheap guard as open-project.jsx. Verified by a project sequence-
|
|
11
|
+
// count increase (never trusting the call's own return value) — cannot
|
|
12
|
+
// name which sequences were imported beyond that (importSequences has no
|
|
13
|
+
// documented return value naming them).
|
|
14
|
+
|
|
15
|
+
function ppb_importSequencesFromProject(argsJson) {
|
|
16
|
+
try {
|
|
17
|
+
var args;
|
|
18
|
+
try {
|
|
19
|
+
args = JSON.parse(argsJson);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!args.projectPath || typeof args.projectPath !== "string") {
|
|
25
|
+
return JSON.stringify({ ok: false, error: "projectPath is required" });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var file = new File(args.projectPath);
|
|
29
|
+
if (!file.exists) {
|
|
30
|
+
return JSON.stringify({ ok: false, error: "no file exists at projectPath: " + args.projectPath });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!app.project) {
|
|
34
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
35
|
+
}
|
|
36
|
+
if (typeof app.project.importSequences !== "function") {
|
|
37
|
+
return JSON.stringify({ ok: false, error: "importSequences is not available on this Premiere build" });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
var hasIds = Object.prototype.toString.call(args.sequenceIds) === "[object Array]" && args.sequenceIds.length > 0;
|
|
41
|
+
|
|
42
|
+
var countBefore = app.project.sequences.numSequences;
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
if (hasIds) {
|
|
46
|
+
app.project.importSequences(args.projectPath, args.sequenceIds);
|
|
47
|
+
} else {
|
|
48
|
+
app.project.importSequences(args.projectPath);
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
return JSON.stringify({ ok: false, error: "importSequences() failed: " + e.toString() });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var countAfter = app.project.sequences.numSequences;
|
|
55
|
+
var imported = countAfter > countBefore;
|
|
56
|
+
|
|
57
|
+
if (!imported) {
|
|
58
|
+
return JSON.stringify({
|
|
59
|
+
ok: false,
|
|
60
|
+
error: "importSequences() did not throw, but the project's sequence count did not increase",
|
|
61
|
+
countBefore: countBefore,
|
|
62
|
+
countAfter: countAfter
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return JSON.stringify({
|
|
67
|
+
ok: true,
|
|
68
|
+
result: {
|
|
69
|
+
imported: true,
|
|
70
|
+
projectPath: args.projectPath,
|
|
71
|
+
sequenceIds: hasIds ? args.sequenceIds : null,
|
|
72
|
+
allSequences: !hasIds,
|
|
73
|
+
countBefore: countBefore,
|
|
74
|
+
countAfter: countAfter
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Command: insert-from-source → ppb_insertFromSource
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (secondsToTicksString,
|
|
4
|
+
// timeValueToSeconds, serializeTrackItem, findSequenceByName,
|
|
5
|
+
// ppbAddToTimeline_cleanupLinkedAudio) are already defined there.
|
|
6
|
+
//
|
|
7
|
+
// Ported from leancoderkavy's premiere-pro-mcp source-monitor.ts
|
|
8
|
+
// insert_from_source — a 3-point insert edit of whatever clip is open in
|
|
9
|
+
// the Source Monitor (its own in/out points, set via set-source-in-out,
|
|
10
|
+
// combine with the sequence's insertClip() call) at either the given
|
|
11
|
+
// atSeconds or the sequence's current playhead. -1 is passed for the
|
|
12
|
+
// non-addressed track index, same convention as add-to-timeline.
|
|
13
|
+
//
|
|
14
|
+
// ⚠️ Same auto-linked-audio trap as add-to-timeline: a video placement
|
|
15
|
+
// whose source item also carries audio can silently land linked audio on
|
|
16
|
+
// some audio track even with audioTrackIndex -1. The shared cleanup
|
|
17
|
+
// helper (ppbAddToTimeline_cleanupLinkedAudio, host/index.jsx) is reused
|
|
18
|
+
// here unchanged for video placements.
|
|
19
|
+
//
|
|
20
|
+
// MUTATION RULE: verified the same way as add-to-timeline — never trust
|
|
21
|
+
// insertClip()'s own return value. LIVE FINDING (add-to-timeline,
|
|
22
|
+
// 2026-07-17): insertClip/overwriteClip IGNORE their track index argument
|
|
23
|
+
// on this build, so the actual landing track is discovered by re-scanning
|
|
24
|
+
// the timeline afterward and reported alongside trackHonored, exactly like
|
|
25
|
+
// add-to-timeline.
|
|
26
|
+
function ppb_insertFromSource(argsJson) {
|
|
27
|
+
try {
|
|
28
|
+
var args;
|
|
29
|
+
try {
|
|
30
|
+
args = JSON.parse(argsJson);
|
|
31
|
+
} catch (e) {
|
|
32
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
36
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
37
|
+
}
|
|
38
|
+
if (typeof args.trackIndex !== "number") {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "trackIndex is required" });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!app.project) {
|
|
43
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var seq = null;
|
|
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
|
+
|
|
59
|
+
var item = null;
|
|
60
|
+
try {
|
|
61
|
+
item = app.sourceMonitor.getProjectItem();
|
|
62
|
+
} catch (e2) {
|
|
63
|
+
return JSON.stringify({ ok: false, error: "app.sourceMonitor.getProjectItem() failed: " + e2.toString() });
|
|
64
|
+
}
|
|
65
|
+
if (!item) {
|
|
66
|
+
return JSON.stringify({ ok: false, error: "no clip open in Source Monitor" });
|
|
67
|
+
}
|
|
68
|
+
var itemNodeId = null;
|
|
69
|
+
try { itemNodeId = item.nodeId; } catch (e3) { itemNodeId = null; }
|
|
70
|
+
|
|
71
|
+
var atSeconds = null;
|
|
72
|
+
var posTicks = null;
|
|
73
|
+
if (typeof args.atSeconds === "number" && !isNaN(args.atSeconds)) {
|
|
74
|
+
atSeconds = args.atSeconds;
|
|
75
|
+
posTicks = secondsToTicksString(atSeconds);
|
|
76
|
+
} else {
|
|
77
|
+
try {
|
|
78
|
+
var playerPos = seq.getPlayerPosition();
|
|
79
|
+
posTicks = playerPos.ticks;
|
|
80
|
+
atSeconds = timeValueToSeconds(playerPos);
|
|
81
|
+
} catch (e4) {
|
|
82
|
+
return JSON.stringify({ ok: false, error: "atSeconds was not given and seq.getPlayerPosition() failed: " + e4.toString() });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
87
|
+
var numTracks;
|
|
88
|
+
try { numTracks = trackCollection.numTracks; } catch (e5) { numTracks = 0; }
|
|
89
|
+
if (args.trackIndex >= numTracks) {
|
|
90
|
+
return JSON.stringify({ ok: false, error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)" });
|
|
91
|
+
}
|
|
92
|
+
var targetTrack = trackCollection[args.trackIndex];
|
|
93
|
+
var trackClipCountBefore = null;
|
|
94
|
+
try { trackClipCountBefore = targetTrack.clips.numItems; } catch (e6) { trackClipCountBefore = null; }
|
|
95
|
+
|
|
96
|
+
var vIdx = args.trackType === "video" ? args.trackIndex : -1;
|
|
97
|
+
var aIdx = args.trackType === "audio" ? args.trackIndex : -1;
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
seq.insertClip(item, posTicks, vIdx, aIdx);
|
|
101
|
+
} catch (e7) {
|
|
102
|
+
return JSON.stringify({ ok: false, error: "seq.insertClip() failed: " + e7.toString() });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
var trackClipCountAfter = null;
|
|
106
|
+
try { trackClipCountAfter = targetTrack.clips.numItems; } catch (e8) { trackClipCountAfter = null; }
|
|
107
|
+
|
|
108
|
+
var toleranceSeconds = 0.1;
|
|
109
|
+
function ppbInsertFromSource_locate() {
|
|
110
|
+
try {
|
|
111
|
+
for (var t2 = 0; t2 < trackCollection.numTracks; t2++) {
|
|
112
|
+
var scanTrack = trackCollection[t2];
|
|
113
|
+
for (var c2 = 0; c2 < scanTrack.clips.numItems; c2++) {
|
|
114
|
+
var candidate = scanTrack.clips[c2];
|
|
115
|
+
var candNodeId = null;
|
|
116
|
+
try { candNodeId = candidate.projectItem.nodeId; } catch (e9) { candNodeId = null; }
|
|
117
|
+
if (candNodeId !== itemNodeId) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
var candStart = null;
|
|
121
|
+
try { candStart = timeValueToSeconds(candidate.start); } catch (e10) { candStart = null; }
|
|
122
|
+
if (candStart !== null && Math.abs(candStart - atSeconds) <= toleranceSeconds) {
|
|
123
|
+
return serializeTrackItem(candidate, t2, c2);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (e11) {
|
|
128
|
+
// fall through
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
var placedClip = ppbInsertFromSource_locate();
|
|
134
|
+
var trackHonored = placedClip !== null && placedClip.trackIndex === args.trackIndex;
|
|
135
|
+
|
|
136
|
+
var linkedAudioCleanup = { performed: false, removedCount: 0, removed: [] };
|
|
137
|
+
if (args.trackType === "video") {
|
|
138
|
+
var removedList = ppbAddToTimeline_cleanupLinkedAudio(seq, itemNodeId, atSeconds, toleranceSeconds);
|
|
139
|
+
linkedAudioCleanup = { performed: true, removedCount: removedList.length, removed: removedList };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return JSON.stringify({
|
|
143
|
+
ok: true,
|
|
144
|
+
result: {
|
|
145
|
+
sequenceName: seq.name,
|
|
146
|
+
inserted: true,
|
|
147
|
+
trackType: args.trackType,
|
|
148
|
+
requestedTrackIndex: args.trackIndex,
|
|
149
|
+
actualTrackIndex: placedClip !== null ? placedClip.trackIndex : null,
|
|
150
|
+
trackHonored: trackHonored,
|
|
151
|
+
atSeconds: atSeconds,
|
|
152
|
+
item: { name: (function () { try { return item.name; } catch (e) { return null; } })(), nodeId: itemNodeId },
|
|
153
|
+
placedClip: placedClip,
|
|
154
|
+
trackClipCountBefore: trackClipCountBefore,
|
|
155
|
+
trackClipCountAfter: trackClipCountAfter,
|
|
156
|
+
linkedAudioCleanup: linkedAudioCleanup
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
161
|
+
}
|
|
162
|
+
}
|