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,120 @@
|
|
|
1
|
+
// Command: add-to-render-queue → ppb_addToRenderQueue
|
|
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
|
+
// Queues the given (or active) sequence for export in Adobe Media Encoder
|
|
7
|
+
// via app.encoder.launchEncoder() + encodeSequence() + startBatch()
|
|
8
|
+
// (PREMIERE_API_NOTES.md's "Export via AME" line). **Fire-and-forget**:
|
|
9
|
+
// there is no progress API — encodeSequence() returns as soon as the job
|
|
10
|
+
// is queued, long before AME finishes writing the file, so this command
|
|
11
|
+
// can NEVER verify the output file the way the exportAsMediaDirect-based
|
|
12
|
+
// commands (export-sequence, extract-audio-track) do. Callers must poll
|
|
13
|
+
// the output path themselves (or use get-render-queue-status, itself only
|
|
14
|
+
// an isRunning() probe) — presetPath MUST be an absolute .epr file path;
|
|
15
|
+
// a bare name like "H.264" silently fails with no jobID per
|
|
16
|
+
// PREMIERE_API_NOTES.md.
|
|
17
|
+
|
|
18
|
+
// range → workAreaType, same mapping as export-sequence's
|
|
19
|
+
// ppbExportSequenceRangeToWorkAreaType (duplicated here since each command
|
|
20
|
+
// file loads independently and cannot rely on another command file's
|
|
21
|
+
// helpers).
|
|
22
|
+
function ppbAddToRenderQueueRangeToWorkAreaType(range) {
|
|
23
|
+
if (range === "entire" || range === undefined || range === null) {
|
|
24
|
+
return { value: 0, label: "entire" };
|
|
25
|
+
}
|
|
26
|
+
if (range === "in-to-out") {
|
|
27
|
+
return { value: 1, label: "in-to-out" };
|
|
28
|
+
}
|
|
29
|
+
if (range === "work-area") {
|
|
30
|
+
return { value: 2, label: "work-area" };
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function ppb_addToRenderQueue(argsJson) {
|
|
36
|
+
try {
|
|
37
|
+
var args;
|
|
38
|
+
try {
|
|
39
|
+
args = JSON.parse(argsJson);
|
|
40
|
+
} catch (e) {
|
|
41
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!args.outputPath || typeof args.outputPath !== "string") {
|
|
45
|
+
return JSON.stringify({ ok: false, error: "outputPath is required" });
|
|
46
|
+
}
|
|
47
|
+
if (!args.presetPath || typeof args.presetPath !== "string") {
|
|
48
|
+
return JSON.stringify({ ok: false, error: "presetPath is required (an absolute .epr file path)" });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!app.project) {
|
|
52
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var seq = null;
|
|
56
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
57
|
+
seq = findSequenceByName(args.sequenceName);
|
|
58
|
+
if (!seq) {
|
|
59
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
seq = app.project.activeSequence;
|
|
63
|
+
if (!seq) {
|
|
64
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var rangeInfo = ppbAddToRenderQueueRangeToWorkAreaType(args.range);
|
|
69
|
+
if (!rangeInfo) {
|
|
70
|
+
return JSON.stringify({ ok: false, error: "range must be one of \"entire\", \"in-to-out\", \"work-area\"" });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
var presetFile = new File(args.presetPath);
|
|
74
|
+
if (!presetFile.exists) {
|
|
75
|
+
return JSON.stringify({ ok: false, error: "preset file not found: " + args.presetPath });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var startBatch = args.startBatch === true;
|
|
79
|
+
|
|
80
|
+
if (!app.encoder) {
|
|
81
|
+
return JSON.stringify({ ok: false, error: "Adobe Media Encoder is not available (app.encoder is undefined)" });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
app.encoder.launchEncoder();
|
|
86
|
+
} catch (e) {
|
|
87
|
+
return JSON.stringify({ ok: false, error: "app.encoder.launchEncoder() failed: " + e.toString() });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
app.encoder.encodeSequence(seq, args.outputPath, args.presetPath, rangeInfo.value, 1 /* removeOnCompletion */);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
return JSON.stringify({ ok: false, error: "app.encoder.encodeSequence() failed: " + e.toString() });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (startBatch) {
|
|
97
|
+
try {
|
|
98
|
+
app.encoder.startBatch();
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return JSON.stringify({ ok: false, error: "job was queued but app.encoder.startBatch() failed: " + e.toString() });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return JSON.stringify({
|
|
105
|
+
ok: true,
|
|
106
|
+
result: {
|
|
107
|
+
sequenceName: seq.name,
|
|
108
|
+
outputPath: args.outputPath,
|
|
109
|
+
presetPath: args.presetPath,
|
|
110
|
+
range: rangeInfo.label,
|
|
111
|
+
startBatch: startBatch,
|
|
112
|
+
note: "fire-and-forget: the job is queued in Adobe Media Encoder, not exported synchronously — " +
|
|
113
|
+
"there is no progress API, so this result does NOT confirm the output file exists yet. " +
|
|
114
|
+
"Poll outputPath yourself, or leave startBatch false and trigger the batch manually in AME."
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// Command: add-to-timeline → ppb_addToTimeline
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// secondsToTicksString, timeValueToSeconds, serializeTrackItem, ...) are
|
|
5
|
+
// already defined there.
|
|
6
|
+
//
|
|
7
|
+
// Ported from leancoderkavy's premiere-pro-mcp add_to_timeline tool.
|
|
8
|
+
// UPDATED 2026-07-17 after the probe session (see BUILD_FINDINGS.md
|
|
9
|
+
// corrections): placement now goes through the TRACK object's own
|
|
10
|
+
// method — seq.videoTracks[i].insertClip(item, TimeObject) /
|
|
11
|
+
// .overwriteClip(item, TimeObject) — which live-verifiably HONORS the
|
|
12
|
+
// track index, unlike the sequence-level seq.insertClip()/
|
|
13
|
+
// overwriteClip(), which ignore their vIdx argument on this build (the
|
|
14
|
+
// pattern both the antipaster and hetpatel repos converged on). The
|
|
15
|
+
// sequence-level call (-1 as the non-addressed track index) is kept as
|
|
16
|
+
// a fallback if the track method is missing or throws.
|
|
17
|
+
//
|
|
18
|
+
// ⚠️ AUTO-LINKED AUDIO TRAP (PREMIERE_API_NOTES.md): placing a video clip
|
|
19
|
+
// whose source projectItem also has audio can silently place the linked
|
|
20
|
+
// audio on some audio track too, even though we passed audioTrackIndex
|
|
21
|
+
// -1 — and if that lands on top of existing content it can destroy it.
|
|
22
|
+
// Per hetpatel's fix, after any video-track placement we scan every
|
|
23
|
+
// audio track for a clip referencing the SAME projectItem.nodeId within
|
|
24
|
+
// 0.1s of the requested startSeconds and remove it (iterating backwards
|
|
25
|
+
// per track, since removal shifts later indices) — the caller only asked
|
|
26
|
+
// for a video placement, so any such auto-placed audio is unwanted.
|
|
27
|
+
//
|
|
28
|
+
// MUTATION RULE: every mutation here is verified by re-reading the
|
|
29
|
+
// timeline afterward — the target track's clip count before/after, and
|
|
30
|
+
// (best-effort) the newly-placed clip's own serialized state — rather
|
|
31
|
+
// than trusting insertClip()/overwriteClip()'s own (undocumented) return
|
|
32
|
+
// value.
|
|
33
|
+
|
|
34
|
+
function ppbFindItemAddToTimeline_walk(item, args, depth) {
|
|
35
|
+
if (depth > 32) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
var isBin = false;
|
|
39
|
+
try {
|
|
40
|
+
isBin = typeof ProjectItemType !== "undefined" && item.type === ProjectItemType.BIN;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
isBin = false;
|
|
43
|
+
}
|
|
44
|
+
var matched = false;
|
|
45
|
+
if (args.nodeId !== null) {
|
|
46
|
+
try { matched = item.nodeId === args.nodeId; } catch (e) { matched = false; }
|
|
47
|
+
} else if (args.name !== null) {
|
|
48
|
+
try { matched = item.name === args.name; } catch (e) { matched = false; }
|
|
49
|
+
}
|
|
50
|
+
if (matched) {
|
|
51
|
+
return item;
|
|
52
|
+
}
|
|
53
|
+
if (isBin && item.children) {
|
|
54
|
+
for (var i = 0; i < item.children.numItems; i++) {
|
|
55
|
+
var found = ppbFindItemAddToTimeline_walk(item.children[i], args, depth + 1);
|
|
56
|
+
if (found) {
|
|
57
|
+
return found;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function ppbFindItemAddToTimeline_resolve(args) {
|
|
65
|
+
var root = app.project.rootItem;
|
|
66
|
+
for (var i = 0; i < root.children.numItems; i++) {
|
|
67
|
+
var found = ppbFindItemAddToTimeline_walk(root.children[i], args, 1);
|
|
68
|
+
if (found) {
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Removes every audio clip on ANY audio track whose source projectItem
|
|
76
|
+
// matches nodeId and whose start is within toleranceSeconds of
|
|
77
|
+
// targetStartSeconds — the auto-linked-audio cleanup described above.
|
|
78
|
+
// Iterates each track's clips backwards so index shifts from an earlier
|
|
79
|
+
// removal never skip a later match. Returns an array of
|
|
80
|
+
// {trackIndex, name, startSeconds} for whatever was removed.
|
|
81
|
+
function ppbAddToTimeline_cleanupLinkedAudio(seq, nodeId, targetStartSeconds, toleranceSeconds) {
|
|
82
|
+
var removed = [];
|
|
83
|
+
var numAudioTracks;
|
|
84
|
+
try {
|
|
85
|
+
numAudioTracks = seq.audioTracks.numTracks;
|
|
86
|
+
} catch (e) {
|
|
87
|
+
return removed;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (var t = 0; t < numAudioTracks; t++) {
|
|
91
|
+
var track = seq.audioTracks[t];
|
|
92
|
+
var numClips;
|
|
93
|
+
try {
|
|
94
|
+
numClips = track.clips.numItems;
|
|
95
|
+
} catch (e2) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
for (var c = numClips - 1; c >= 0; c--) {
|
|
99
|
+
var clip = track.clips[c];
|
|
100
|
+
var clipNodeId = null;
|
|
101
|
+
try { clipNodeId = clip.projectItem.nodeId; } catch (e3) { clipNodeId = null; }
|
|
102
|
+
if (clipNodeId !== nodeId) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
var clipStart = null;
|
|
106
|
+
try { clipStart = timeValueToSeconds(clip.start); } catch (e4) { clipStart = null; }
|
|
107
|
+
if (clipStart === null || Math.abs(clipStart - targetStartSeconds) > toleranceSeconds) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
var clipName = null;
|
|
111
|
+
try { clipName = clip.name; } catch (e5) { clipName = null; }
|
|
112
|
+
try {
|
|
113
|
+
clip.remove(false, false);
|
|
114
|
+
removed.push({ trackIndex: t, name: clipName, startSeconds: clipStart });
|
|
115
|
+
} catch (e6) {
|
|
116
|
+
// leave it — best-effort cleanup, don't fail the whole command over it
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return removed;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function ppb_addToTimeline(argsJson) {
|
|
124
|
+
try {
|
|
125
|
+
var args;
|
|
126
|
+
try {
|
|
127
|
+
args = JSON.parse(argsJson);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
var hasNodeId = typeof args.nodeId === "string" && args.nodeId.length > 0;
|
|
133
|
+
var hasName = typeof args.name === "string" && args.name.length > 0;
|
|
134
|
+
if (!hasNodeId && !hasName) {
|
|
135
|
+
return JSON.stringify({ ok: false, error: "either nodeId or name is required to identify the project item" });
|
|
136
|
+
}
|
|
137
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
138
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
139
|
+
}
|
|
140
|
+
if (typeof args.trackIndex !== "number") {
|
|
141
|
+
return JSON.stringify({ ok: false, error: "trackIndex is required" });
|
|
142
|
+
}
|
|
143
|
+
if (typeof args.startSeconds !== "number") {
|
|
144
|
+
return JSON.stringify({ ok: false, error: "startSeconds is required" });
|
|
145
|
+
}
|
|
146
|
+
if (args.mode !== "insert" && args.mode !== "overwrite") {
|
|
147
|
+
return JSON.stringify({ ok: false, error: "mode must be \"insert\" or \"overwrite\"" });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!app.project) {
|
|
151
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
var seq = null;
|
|
155
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
156
|
+
seq = findSequenceByName(args.sequenceName);
|
|
157
|
+
if (!seq) {
|
|
158
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
seq = app.project.activeSequence;
|
|
162
|
+
if (!seq) {
|
|
163
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
var item = ppbFindItemAddToTimeline_resolve({
|
|
168
|
+
nodeId: hasNodeId ? args.nodeId : null,
|
|
169
|
+
name: hasNodeId ? null : args.name
|
|
170
|
+
});
|
|
171
|
+
if (!item) {
|
|
172
|
+
return JSON.stringify({ ok: false, error: "no project item found matching the given nodeId/name" });
|
|
173
|
+
}
|
|
174
|
+
var itemNodeId = null;
|
|
175
|
+
try { itemNodeId = item.nodeId; } catch (e7) { itemNodeId = null; }
|
|
176
|
+
|
|
177
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
178
|
+
var numTracks;
|
|
179
|
+
try { numTracks = trackCollection.numTracks; } catch (e8) { numTracks = 0; }
|
|
180
|
+
if (args.trackIndex >= numTracks) {
|
|
181
|
+
return JSON.stringify({ ok: false, error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)" });
|
|
182
|
+
}
|
|
183
|
+
var targetTrack = trackCollection[args.trackIndex];
|
|
184
|
+
var trackClipCountBefore = null;
|
|
185
|
+
try { trackClipCountBefore = targetTrack.clips.numItems; } catch (e9) { trackClipCountBefore = null; }
|
|
186
|
+
|
|
187
|
+
var vIdx = args.trackType === "video" ? args.trackIndex : -1;
|
|
188
|
+
var aIdx = args.trackType === "audio" ? args.trackIndex : -1;
|
|
189
|
+
var startTicks = secondsToTicksString(args.startSeconds);
|
|
190
|
+
var methodName = args.mode === "insert" ? "insertClip" : "overwriteClip";
|
|
191
|
+
|
|
192
|
+
// Track-object placement first — honors the track (live-verified
|
|
193
|
+
// 2026-07-17 with a Time object on video tracks 1 and 2).
|
|
194
|
+
var placementAttempts = [];
|
|
195
|
+
var placedVia = null;
|
|
196
|
+
if (typeof targetTrack[methodName] === "function") {
|
|
197
|
+
var timeObj = new Time();
|
|
198
|
+
timeObj.seconds = args.startSeconds;
|
|
199
|
+
try {
|
|
200
|
+
targetTrack[methodName](item, timeObj);
|
|
201
|
+
placementAttempts.push({ method: "track." + methodName + "(item, TimeObject)", success: true });
|
|
202
|
+
placedVia = "track." + methodName;
|
|
203
|
+
} catch (e10a) {
|
|
204
|
+
placementAttempts.push({ method: "track." + methodName + "(item, TimeObject)", success: false, error: e10a.toString() });
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
placementAttempts.push({ method: "track." + methodName, success: false, error: "not a function on this build" });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Fallback: sequence-level call — known on this build to ignore its
|
|
211
|
+
// video-track index (clip lands on a build-chosen track).
|
|
212
|
+
if (placedVia === null) {
|
|
213
|
+
try {
|
|
214
|
+
if (args.mode === "insert") {
|
|
215
|
+
seq.insertClip(item, startTicks, vIdx, aIdx);
|
|
216
|
+
} else {
|
|
217
|
+
seq.overwriteClip(item, startTicks, vIdx, aIdx);
|
|
218
|
+
}
|
|
219
|
+
placementAttempts.push({ method: "seq." + methodName + "(item, ticks, vIdx, aIdx)", success: true });
|
|
220
|
+
placedVia = "seq." + methodName;
|
|
221
|
+
} catch (e10) {
|
|
222
|
+
return JSON.stringify({
|
|
223
|
+
ok: false,
|
|
224
|
+
error: "both track-level and sequence-level " + methodName + "() failed — see attempts",
|
|
225
|
+
attempts: placementAttempts
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
var trackClipCountAfter = null;
|
|
231
|
+
try { trackClipCountAfter = targetTrack.clips.numItems; } catch (e11) { trackClipCountAfter = null; }
|
|
232
|
+
|
|
233
|
+
// Locate the newly-placed clip by matching projectItem + requested
|
|
234
|
+
// start time — scanning ALL tracks of the type, not just the
|
|
235
|
+
// requested one: live-tested 2026-07-17, seq.overwriteClip() IGNORES
|
|
236
|
+
// its vIdx argument on this Premiere 2026 build (clips landed on V1
|
|
237
|
+
// regardless of vIdx 0 or 1, targeting on or off), so where the clip
|
|
238
|
+
// actually went must be discovered, never assumed.
|
|
239
|
+
var toleranceSeconds = 0.1;
|
|
240
|
+
function ppbAddToTimeline_locate() {
|
|
241
|
+
try {
|
|
242
|
+
for (var t2 = 0; t2 < trackCollection.numTracks; t2++) {
|
|
243
|
+
var scanTrack = trackCollection[t2];
|
|
244
|
+
for (var c2 = 0; c2 < scanTrack.clips.numItems; c2++) {
|
|
245
|
+
var candidate = scanTrack.clips[c2];
|
|
246
|
+
var candNodeId = null;
|
|
247
|
+
try { candNodeId = candidate.projectItem.nodeId; } catch (e12) { candNodeId = null; }
|
|
248
|
+
if (candNodeId !== itemNodeId) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
var candStart = null;
|
|
252
|
+
try { candStart = timeValueToSeconds(candidate.start); } catch (e13) { candStart = null; }
|
|
253
|
+
if (candStart !== null && Math.abs(candStart - args.startSeconds) <= toleranceSeconds) {
|
|
254
|
+
return serializeTrackItem(candidate, t2, c2);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} catch (e14) {
|
|
259
|
+
// fall through
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
var placedClip = ppbAddToTimeline_locate();
|
|
265
|
+
|
|
266
|
+
// The track-object path honors the track; the sequence-level
|
|
267
|
+
// fallback doesn't (build bug) — either way, report the ACTUAL track
|
|
268
|
+
// the clip landed on and flag whether the request was honored.
|
|
269
|
+
var trackHonored = placedClip !== null && placedClip.trackIndex === args.trackIndex;
|
|
270
|
+
|
|
271
|
+
var linkedAudioCleanup = { performed: false, removedCount: 0, removed: [] };
|
|
272
|
+
if (args.trackType === "video") {
|
|
273
|
+
var removedList = ppbAddToTimeline_cleanupLinkedAudio(seq, itemNodeId, args.startSeconds, toleranceSeconds);
|
|
274
|
+
linkedAudioCleanup = { performed: true, removedCount: removedList.length, removed: removedList };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return JSON.stringify({
|
|
278
|
+
ok: true,
|
|
279
|
+
result: {
|
|
280
|
+
sequenceName: seq.name,
|
|
281
|
+
added: true,
|
|
282
|
+
mode: args.mode,
|
|
283
|
+
placedVia: placedVia,
|
|
284
|
+
placementAttempts: placementAttempts,
|
|
285
|
+
trackType: args.trackType,
|
|
286
|
+
requestedTrackIndex: args.trackIndex,
|
|
287
|
+
actualTrackIndex: placedClip !== null ? placedClip.trackIndex : null,
|
|
288
|
+
trackHonored: trackHonored,
|
|
289
|
+
startSeconds: args.startSeconds,
|
|
290
|
+
item: { name: (function () { try { return item.name; } catch (e) { return null; } })(), nodeId: itemNodeId },
|
|
291
|
+
placedClip: placedClip,
|
|
292
|
+
trackClipCountBefore: trackClipCountBefore,
|
|
293
|
+
trackClipCountAfter: trackClipCountAfter,
|
|
294
|
+
linkedAudioCleanup: linkedAudioCleanup
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
} catch (e) {
|
|
298
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Command: add-track → ppb_addTrack
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (ensureQEEnabled,
|
|
4
|
+
// findSequenceByName, ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Merges leancoderkavy's premiere-pro-mcp `add_track` (tracks.ts, standard
|
|
7
|
+
// DOM insertVideoTrackAt/insertAudioTrackAt) and `add_tracks` (advanced.ts,
|
|
8
|
+
// QE addTracks) into one command — the reference project split these into
|
|
9
|
+
// two near-duplicate tools (single-track-type standard-DOM vs. multi-type
|
|
10
|
+
// QE); here `trackType` picks video-or-audio and `count` picks how many.
|
|
11
|
+
//
|
|
12
|
+
// hetpatel's note in PREMIERE_API_NOTES.md warns that a bulk QE addTracks()
|
|
13
|
+
// call can WEDGE the CEP bridge — so even when the QE fallback path is
|
|
14
|
+
// used, this issues exactly one underlying add call per requested track,
|
|
15
|
+
// in a loop, never a single call with count > 1.
|
|
16
|
+
function ppb_addTrack(argsJson) {
|
|
17
|
+
try {
|
|
18
|
+
var args;
|
|
19
|
+
try {
|
|
20
|
+
args = JSON.parse(argsJson);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
26
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
var count = 1;
|
|
30
|
+
if (args.count !== undefined && args.count !== null) {
|
|
31
|
+
if (typeof args.count !== "number" || Math.floor(args.count) !== args.count || args.count < 1) {
|
|
32
|
+
return JSON.stringify({ ok: false, error: "count must be a positive integer" });
|
|
33
|
+
}
|
|
34
|
+
count = args.count;
|
|
35
|
+
}
|
|
36
|
+
if (count > 8) {
|
|
37
|
+
count = 8; // capped — see task spec; guards against a runaway bulk-insert loop
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!app.project) {
|
|
41
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var seq = null;
|
|
45
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
46
|
+
seq = findSequenceByName(args.sequenceName);
|
|
47
|
+
if (!seq) {
|
|
48
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
seq = app.project.activeSequence;
|
|
52
|
+
if (!seq) {
|
|
53
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getTrackCollection() {
|
|
58
|
+
return args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var index = args.index;
|
|
62
|
+
var hasIndex = typeof index === "number" && Math.floor(index) === index && index >= 0;
|
|
63
|
+
|
|
64
|
+
var attemptsLog = [];
|
|
65
|
+
var addedCount = 0;
|
|
66
|
+
var startingCount = getTrackCollection().numTracks;
|
|
67
|
+
|
|
68
|
+
for (var i = 0; i < count; i++) {
|
|
69
|
+
var before = getTrackCollection().numTracks;
|
|
70
|
+
var insertAt = hasIndex ? index : before; // default: append at the end
|
|
71
|
+
var iterationAttempts = [];
|
|
72
|
+
var succeeded = false;
|
|
73
|
+
|
|
74
|
+
// --- Attempt 1: standard-DOM insertVideoTrackAt/insertAudioTrackAt [leancoderkavy] ---
|
|
75
|
+
try {
|
|
76
|
+
if (args.trackType === "video") {
|
|
77
|
+
seq.insertVideoTrackAt(insertAt, 1);
|
|
78
|
+
} else {
|
|
79
|
+
seq.insertAudioTrackAt(insertAt, 1);
|
|
80
|
+
}
|
|
81
|
+
iterationAttempts.push({ form: "insertTrackAt", success: true });
|
|
82
|
+
succeeded = getTrackCollection().numTracks > before;
|
|
83
|
+
} catch (e) {
|
|
84
|
+
iterationAttempts.push({ form: "insertTrackAt", success: false, error: e.toString() });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// --- Attempt 2: seq.addTrack(type[, channelType]) [ayushozha] ---
|
|
88
|
+
if (!succeeded) {
|
|
89
|
+
try {
|
|
90
|
+
if (args.trackType === "video") {
|
|
91
|
+
seq.addTrack("video");
|
|
92
|
+
} else {
|
|
93
|
+
seq.addTrack("audio", 1 /* stereo */);
|
|
94
|
+
}
|
|
95
|
+
iterationAttempts.push({ form: "addTrack", success: true });
|
|
96
|
+
succeeded = getTrackCollection().numTracks > before;
|
|
97
|
+
} catch (e) {
|
|
98
|
+
iterationAttempts.push({ form: "addTrack", success: false, error: e.toString() });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// --- Attempt 3: QE addTracks(...), one track per call (never bulk) ---
|
|
103
|
+
if (!succeeded) {
|
|
104
|
+
try {
|
|
105
|
+
ensureQEEnabled();
|
|
106
|
+
if (app.project.activeSequence !== seq) {
|
|
107
|
+
app.project.activeSequence = seq;
|
|
108
|
+
}
|
|
109
|
+
var qeSeq = qe.project.getActiveSequence();
|
|
110
|
+
if (!qeSeq) {
|
|
111
|
+
throw new Error("qe.project.getActiveSequence() returned nothing");
|
|
112
|
+
}
|
|
113
|
+
if (args.trackType === "video") {
|
|
114
|
+
// hetpatel 7-arg form: (videoCount, videoInsertIndex, audioCount, audioInsertIndex, audioMediaType, submixCount, submixInsertIndex)
|
|
115
|
+
qeSeq.addTracks(1, insertAt, 0, 0, 1, 0, 0);
|
|
116
|
+
} else {
|
|
117
|
+
// hetpatel 7-arg form, audio side
|
|
118
|
+
qeSeq.addTracks(0, 0, 1, insertAt, 1, 0, 0);
|
|
119
|
+
}
|
|
120
|
+
iterationAttempts.push({ form: "qeAddTracks7Arg", success: true });
|
|
121
|
+
succeeded = getTrackCollection().numTracks > before;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
iterationAttempts.push({ form: "qeAddTracks7Arg", success: false, error: e.toString() });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// --- Attempt 4: QE addTracks(...) leancoderkavy's 4-arg form, one track per call ---
|
|
128
|
+
if (!succeeded) {
|
|
129
|
+
try {
|
|
130
|
+
ensureQEEnabled();
|
|
131
|
+
if (app.project.activeSequence !== seq) {
|
|
132
|
+
app.project.activeSequence = seq;
|
|
133
|
+
}
|
|
134
|
+
var qeSeq2 = qe.project.getActiveSequence();
|
|
135
|
+
if (!qeSeq2) {
|
|
136
|
+
throw new Error("qe.project.getActiveSequence() returned nothing");
|
|
137
|
+
}
|
|
138
|
+
if (args.trackType === "video") {
|
|
139
|
+
qeSeq2.addTracks(1, 0, 0, 0);
|
|
140
|
+
} else {
|
|
141
|
+
qeSeq2.addTracks(0, 1, 0, 0);
|
|
142
|
+
}
|
|
143
|
+
iterationAttempts.push({ form: "qeAddTracks4Arg", success: true });
|
|
144
|
+
succeeded = getTrackCollection().numTracks > before;
|
|
145
|
+
} catch (e) {
|
|
146
|
+
iterationAttempts.push({ form: "qeAddTracks4Arg", success: false, error: e.toString() });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
attemptsLog.push({ trackNumber: i + 1, attempts: iterationAttempts, succeeded: succeeded });
|
|
151
|
+
|
|
152
|
+
if (succeeded) {
|
|
153
|
+
addedCount++;
|
|
154
|
+
} else {
|
|
155
|
+
// Stop retrying further tracks once one iteration fails outright —
|
|
156
|
+
// no known form worked, so more attempts at the same op would just
|
|
157
|
+
// repeat the same failures.
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var finalCount = getTrackCollection().numTracks;
|
|
163
|
+
var result = {
|
|
164
|
+
sequenceName: seq.name,
|
|
165
|
+
trackType: args.trackType,
|
|
166
|
+
requestedCount: count,
|
|
167
|
+
added: addedCount,
|
|
168
|
+
startingTrackCount: startingCount,
|
|
169
|
+
totalTracks: finalCount,
|
|
170
|
+
attempts: attemptsLog
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if (addedCount === 0) {
|
|
174
|
+
return JSON.stringify({
|
|
175
|
+
ok: false,
|
|
176
|
+
error: "could not add any " + args.trackType + " track with any known form (insertTrackAt, addTrack, QE addTracks 7-arg, QE addTracks 4-arg)",
|
|
177
|
+
attempts: attemptsLog
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (addedCount < count) {
|
|
181
|
+
result.warning = "only added " + addedCount + " of " + count + " requested tracks before a failure";
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return JSON.stringify({ ok: true, result: result });
|
|
185
|
+
} catch (e) {
|
|
186
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
187
|
+
}
|
|
188
|
+
}
|