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,192 @@
|
|
|
1
|
+
// Command: remove-keyframe → ppb_removeKeyframe
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// findClipComponent, findComponentProperty, timeValueToSeconds,
|
|
5
|
+
// keyTimeToSeconds, tryTimeForms, getSequenceFps, ...) are already defined
|
|
6
|
+
// there.
|
|
7
|
+
//
|
|
8
|
+
// Standard-DOM mutation. Ported from leancoderkavy's premiere-pro-mcp
|
|
9
|
+
// `remove_keyframe` tool (keyframes.ts), addressed here by
|
|
10
|
+
// trackType/trackIndex/clipIndex + componentName/propertyName. `seconds`
|
|
11
|
+
// is clip-relative, offset by clip.start to sequence time. Tolerance is
|
|
12
|
+
// fixed at HALF A FRAME (0.5 / sequence fps) either side of the requested
|
|
13
|
+
// time, per the task spec — this is the cleanup path for add-keyframe
|
|
14
|
+
// mistakes (undo is non-functional on this build), so it first tries to
|
|
15
|
+
// locate an EXISTING key within tolerance via getKeys() (removing that
|
|
16
|
+
// exact key object, most likely to succeed), falling back to constructing
|
|
17
|
+
// a fresh time argument at the requested position via tryTimeForms() if no
|
|
18
|
+
// existing key matched or getKeys() itself is unavailable. Verified via a
|
|
19
|
+
// getKeys() COUNT drop, not by confirming which key vanished.
|
|
20
|
+
function ppb_removeKeyframe(argsJson) {
|
|
21
|
+
try {
|
|
22
|
+
var args;
|
|
23
|
+
try {
|
|
24
|
+
args = JSON.parse(argsJson);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (args.trackType !== "video" && args.trackType !== "audio") {
|
|
30
|
+
return JSON.stringify({ ok: false, error: "trackType must be \"video\" or \"audio\"" });
|
|
31
|
+
}
|
|
32
|
+
if (typeof args.trackIndex !== "number" || args.trackIndex < 0 || Math.floor(args.trackIndex) !== args.trackIndex) {
|
|
33
|
+
return JSON.stringify({ ok: false, error: "trackIndex must be a non-negative integer" });
|
|
34
|
+
}
|
|
35
|
+
if (typeof args.clipIndex !== "number" || args.clipIndex < 0 || Math.floor(args.clipIndex) !== args.clipIndex) {
|
|
36
|
+
return JSON.stringify({ ok: false, error: "clipIndex must be a non-negative integer" });
|
|
37
|
+
}
|
|
38
|
+
if (typeof args.componentName !== "string" || !args.componentName) {
|
|
39
|
+
return JSON.stringify({ ok: false, error: "componentName is required" });
|
|
40
|
+
}
|
|
41
|
+
if (typeof args.propertyName !== "string" || !args.propertyName) {
|
|
42
|
+
return JSON.stringify({ ok: false, error: "propertyName is required" });
|
|
43
|
+
}
|
|
44
|
+
if (typeof args.seconds !== "number") {
|
|
45
|
+
return JSON.stringify({ ok: false, error: "seconds must be a number (clip-relative)" });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!app.project) {
|
|
49
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var seq = null;
|
|
53
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
54
|
+
seq = findSequenceByName(args.sequenceName);
|
|
55
|
+
if (!seq) {
|
|
56
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
seq = app.project.activeSequence;
|
|
60
|
+
if (!seq) {
|
|
61
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var trackCollection = args.trackType === "video" ? seq.videoTracks : seq.audioTracks;
|
|
66
|
+
var numTracks = trackCollection.numTracks;
|
|
67
|
+
if (args.trackIndex >= numTracks) {
|
|
68
|
+
return JSON.stringify({
|
|
69
|
+
ok: false,
|
|
70
|
+
error: "trackIndex " + args.trackIndex + " is out of range — sequence has " + numTracks + " " + args.trackType + " track(s)"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var track = trackCollection[args.trackIndex];
|
|
75
|
+
var numClips = track.clips.numItems;
|
|
76
|
+
if (args.clipIndex >= numClips) {
|
|
77
|
+
return JSON.stringify({
|
|
78
|
+
ok: false,
|
|
79
|
+
error: "clipIndex " + args.clipIndex + " is out of range — track " + args.trackIndex + " has " + numClips + " clip(s)"
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var clip = track.clips[args.clipIndex];
|
|
84
|
+
var clipName = null;
|
|
85
|
+
try { clipName = clip.name; } catch (e) { clipName = null; }
|
|
86
|
+
|
|
87
|
+
var clipStartSeconds = 0;
|
|
88
|
+
try { clipStartSeconds = timeValueToSeconds(clip.start) || 0; } catch (e) { clipStartSeconds = 0; }
|
|
89
|
+
|
|
90
|
+
var comp = findClipComponent(clip, [args.componentName], [args.componentName]);
|
|
91
|
+
if (!comp) {
|
|
92
|
+
return JSON.stringify({
|
|
93
|
+
ok: false,
|
|
94
|
+
error: "component \"" + args.componentName + "\" not found on clip (matched against matchName and displayName)"
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
var compDisplayName = null;
|
|
98
|
+
try { compDisplayName = comp.displayName; } catch (e) { compDisplayName = null; }
|
|
99
|
+
|
|
100
|
+
var prop = findComponentProperty(comp, [args.propertyName]);
|
|
101
|
+
if (!prop) {
|
|
102
|
+
return JSON.stringify({
|
|
103
|
+
ok: false,
|
|
104
|
+
error: "property \"" + args.propertyName + "\" not found on component \"" + compDisplayName + "\""
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var fps = 30;
|
|
109
|
+
try { fps = getSequenceFps(seq) || 30; } catch (e) { fps = 30; }
|
|
110
|
+
var toleranceSeconds = 0.5 / fps;
|
|
111
|
+
|
|
112
|
+
var sequenceSeconds = clipStartSeconds + args.seconds;
|
|
113
|
+
|
|
114
|
+
var keyCountBefore = 0;
|
|
115
|
+
var rawKeys = null;
|
|
116
|
+
try {
|
|
117
|
+
rawKeys = prop.getKeys();
|
|
118
|
+
keyCountBefore = rawKeys ? rawKeys.length : 0;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
keyCountBefore = null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
var matchedKey = null;
|
|
124
|
+
var matchedSeconds = null;
|
|
125
|
+
if (rawKeys) {
|
|
126
|
+
for (var i = 0; i < rawKeys.length; i++) {
|
|
127
|
+
var ks = null;
|
|
128
|
+
try { ks = keyTimeToSeconds(rawKeys[i]); } catch (e1) { ks = null; }
|
|
129
|
+
if (ks !== null && Math.abs(ks - sequenceSeconds) <= toleranceSeconds) {
|
|
130
|
+
matchedKey = rawKeys[i];
|
|
131
|
+
matchedSeconds = ks;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var removeAttempts = [];
|
|
138
|
+
var removed = false;
|
|
139
|
+
|
|
140
|
+
if (matchedKey !== null) {
|
|
141
|
+
try {
|
|
142
|
+
prop.removeKey(matchedKey);
|
|
143
|
+
removeAttempts.push({ form: "existingKeyObject", success: true });
|
|
144
|
+
removed = true;
|
|
145
|
+
} catch (e2) {
|
|
146
|
+
removeAttempts.push({ form: "existingKeyObject", success: false, error: e2.toString() });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!removed) {
|
|
151
|
+
var tf = tryTimeForms(sequenceSeconds, function (t) {
|
|
152
|
+
prop.removeKey(t);
|
|
153
|
+
});
|
|
154
|
+
removeAttempts = removeAttempts.concat(tf.attempts);
|
|
155
|
+
removed = tf.success;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
var keyCountAfter = 0;
|
|
159
|
+
try {
|
|
160
|
+
var keysAfter = prop.getKeys();
|
|
161
|
+
keyCountAfter = keysAfter ? keysAfter.length : 0;
|
|
162
|
+
} catch (e3) {
|
|
163
|
+
keyCountAfter = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
var verified = (keyCountBefore !== null && keyCountAfter !== null && keyCountAfter === keyCountBefore - 1);
|
|
167
|
+
|
|
168
|
+
return JSON.stringify({
|
|
169
|
+
ok: true,
|
|
170
|
+
result: {
|
|
171
|
+
sequenceName: seq.name,
|
|
172
|
+
trackType: args.trackType,
|
|
173
|
+
trackIndex: args.trackIndex,
|
|
174
|
+
clipIndex: args.clipIndex,
|
|
175
|
+
clipName: clipName,
|
|
176
|
+
componentName: compDisplayName,
|
|
177
|
+
propertyName: args.propertyName,
|
|
178
|
+
seconds: args.seconds,
|
|
179
|
+
sequenceSeconds: sequenceSeconds,
|
|
180
|
+
toleranceSeconds: toleranceSeconds,
|
|
181
|
+
matchedExistingKey: matchedKey !== null,
|
|
182
|
+
matchedSeconds: matchedSeconds,
|
|
183
|
+
removeAttempts: removeAttempts,
|
|
184
|
+
keyCountBefore: keyCountBefore,
|
|
185
|
+
keyCountAfter: keyCountAfter,
|
|
186
|
+
verified: verified
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
} catch (e) {
|
|
190
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Command: remove-selected-clips → ppb_removeSelectedClips
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (findSequenceByName,
|
|
4
|
+
// serializeTrackItem, ...) are already defined there.
|
|
5
|
+
//
|
|
6
|
+
// Ported from leancoderkavy/premiere-pro-mcp's track-targeting.ts
|
|
7
|
+
// remove_selected_clips. Removes every currently-selected clip (video+
|
|
8
|
+
// audio) via clip.remove(rippleBool, /*alignToVideo*/true). Selected
|
|
9
|
+
// clips are collected BACKWARDS per track (highest clipIndex first) so
|
|
10
|
+
// that removing one clip never invalidates the still-pending indices of
|
|
11
|
+
// clips before it on the same track — a ripple=true removal shifts every
|
|
12
|
+
// later clip on that track.
|
|
13
|
+
//
|
|
14
|
+
// Destructive: removed clips cannot be restored (undo is non-functional
|
|
15
|
+
// on this build per README.md) — verify on a duplicate/throwaway
|
|
16
|
+
// sequence before running against real footage.
|
|
17
|
+
//
|
|
18
|
+
// Verification: total clip count across all tracks, before/after, plus a
|
|
19
|
+
// per-clip removed/failed breakdown (never trusting remove()'s own return
|
|
20
|
+
// value — same rule as every other mutation command in this panel).
|
|
21
|
+
function ppb_countAllClips(seq) {
|
|
22
|
+
var total = 0;
|
|
23
|
+
try {
|
|
24
|
+
for (var v = 0; v < seq.videoTracks.numTracks; v++) {
|
|
25
|
+
total += seq.videoTracks[v].clips.numItems;
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// best-effort
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
for (var a = 0; a < seq.audioTracks.numTracks; a++) {
|
|
32
|
+
total += seq.audioTracks[a].clips.numItems;
|
|
33
|
+
}
|
|
34
|
+
} catch (e) {
|
|
35
|
+
// best-effort
|
|
36
|
+
}
|
|
37
|
+
return total;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ppb_removeSelectedClips(argsJson) {
|
|
41
|
+
try {
|
|
42
|
+
var args;
|
|
43
|
+
try {
|
|
44
|
+
args = JSON.parse(argsJson);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!app.project) {
|
|
50
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var seq = null;
|
|
54
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
55
|
+
seq = findSequenceByName(args.sequenceName);
|
|
56
|
+
if (!seq) {
|
|
57
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
seq = app.project.activeSequence;
|
|
61
|
+
if (!seq) {
|
|
62
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
var ripple = args.ripple === true;
|
|
67
|
+
|
|
68
|
+
var toRemove = [];
|
|
69
|
+
function collectSelectedBackwards(tracks, trackType) {
|
|
70
|
+
for (var t = 0; t < tracks.numTracks; t++) {
|
|
71
|
+
for (var c = tracks[t].clips.numItems - 1; c >= 0; c--) {
|
|
72
|
+
var clip = tracks[t].clips[c];
|
|
73
|
+
var isSel = false;
|
|
74
|
+
try { isSel = clip.isSelected(); } catch (e) { isSel = false; }
|
|
75
|
+
if (isSel) {
|
|
76
|
+
var name = null;
|
|
77
|
+
try { name = clip.name; } catch (e2) { name = null; }
|
|
78
|
+
toRemove.push({ clip: clip, trackType: trackType, trackIndex: t, clipIndex: c, name: name });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
collectSelectedBackwards(seq.videoTracks, "video");
|
|
84
|
+
collectSelectedBackwards(seq.audioTracks, "audio");
|
|
85
|
+
|
|
86
|
+
var countBefore = ppb_countAllClips(seq);
|
|
87
|
+
|
|
88
|
+
var results = [];
|
|
89
|
+
var removedCount = 0;
|
|
90
|
+
for (var i = 0; i < toRemove.length; i++) {
|
|
91
|
+
var entry = toRemove[i];
|
|
92
|
+
var removeError = null;
|
|
93
|
+
try {
|
|
94
|
+
entry.clip.remove(ripple, true);
|
|
95
|
+
removedCount++;
|
|
96
|
+
} catch (e) {
|
|
97
|
+
removeError = e.toString();
|
|
98
|
+
}
|
|
99
|
+
results.push({
|
|
100
|
+
trackType: entry.trackType,
|
|
101
|
+
trackIndex: entry.trackIndex,
|
|
102
|
+
clipIndex: entry.clipIndex,
|
|
103
|
+
name: entry.name,
|
|
104
|
+
error: removeError
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
var countAfter = ppb_countAllClips(seq);
|
|
109
|
+
|
|
110
|
+
return JSON.stringify({
|
|
111
|
+
ok: true,
|
|
112
|
+
result: {
|
|
113
|
+
sequenceName: seq.name,
|
|
114
|
+
ripple: ripple,
|
|
115
|
+
selectedCount: toRemove.length,
|
|
116
|
+
removedCount: removedCount,
|
|
117
|
+
countBefore: countBefore,
|
|
118
|
+
countAfter: countAfter,
|
|
119
|
+
verified: countAfter === countBefore - removedCount,
|
|
120
|
+
results: results
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
} catch (e) {
|
|
124
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Command: remove-track-intervals → ppb_removeTrackIntervals
|
|
2
|
+
// Loaded lazily by ppb_dispatch (host/index.jsx) on first use, into the
|
|
3
|
+
// same global ExtendScript context — shared helpers (ensureQEEnabled,
|
|
4
|
+
// findSequenceByName, getSequenceFps, timecodeToSeconds, ...) are already
|
|
5
|
+
// defined there.
|
|
6
|
+
//
|
|
7
|
+
// Ripple-deletes a list of time intervals from an audio track (and,
|
|
8
|
+
// optionally, from one or more linked video tracks so they stay in
|
|
9
|
+
// sync), via the QE DOM's razor() + a rippleDelete()/remove() fallback
|
|
10
|
+
// whose success is judged by an actual numItems drop, not either call's
|
|
11
|
+
// return value (both are unreliable in practice on this Premiere
|
|
12
|
+
// version). Adapted from a proven implementation in a sibling project.
|
|
13
|
+
//
|
|
14
|
+
// QE DOM operates on qe.project.getActiveSequence() only — whichever
|
|
15
|
+
// sequence tab is frontmost — so this command makes the resolved
|
|
16
|
+
// sequence the active one first (app.project.activeSequence = seq)
|
|
17
|
+
// rather than erroring if it isn't already.
|
|
18
|
+
|
|
19
|
+
function toQeTimecode(timecode) {
|
|
20
|
+
// remove_pauses.py's frames_to_timecode() emits total elapsed minutes with
|
|
21
|
+
// no 60-minute cap (e.g. 75 minutes in prints as "75:03:12"), so MM here
|
|
22
|
+
// can exceed 59 for any sequence over an hour. QE razor() wants a genuine
|
|
23
|
+
// "HH:MM:SS:FF" with minutes in [0,59], so carry the excess into hours
|
|
24
|
+
// rather than assuming MM is always sub-hour.
|
|
25
|
+
var parts = timecode.split(":");
|
|
26
|
+
var totalMinutes = parseInt(parts[0], 10);
|
|
27
|
+
var seconds = parts[1];
|
|
28
|
+
var frames = parts[2];
|
|
29
|
+
var hours = Math.floor(totalMinutes / 60);
|
|
30
|
+
var minutes = totalMinutes % 60;
|
|
31
|
+
function pad2(n) {
|
|
32
|
+
return (n < 10 ? "0" : "") + n;
|
|
33
|
+
}
|
|
34
|
+
return pad2(hours) + ":" + pad2(minutes) + ":" + seconds + ":" + frames;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function findAndRemoveInRange(qeTrack, startSeconds, endSeconds, tolerance, warnings, trackLabel) {
|
|
38
|
+
var matches = [];
|
|
39
|
+
for (var k = 0; k < qeTrack.numItems; k++) {
|
|
40
|
+
var item = qeTrack.getItemAt(k);
|
|
41
|
+
// QE track items include "Empty" gap placeholders alongside real
|
|
42
|
+
// "Clip" items (confirmed earlier this session, see QE_DOM_NOTES.md).
|
|
43
|
+
// Razoring both boundaries of a pause can leave an Empty item bounded
|
|
44
|
+
// by the same tolerance window as the real Clip we actually want to
|
|
45
|
+
// remove — attempting to remove an Empty item is a harmless no-op
|
|
46
|
+
// (there's nothing there), but it was previously misreported as a
|
|
47
|
+
// removal failure. Skip non-Clip items so warnings only fire for
|
|
48
|
+
// genuine failures.
|
|
49
|
+
if (item.type !== "Clip") {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
var itemStart = Number(item.start.ticks) / TICKS_PER_SECOND;
|
|
53
|
+
var itemEnd = Number(item.end.ticks) / TICKS_PER_SECOND;
|
|
54
|
+
if (itemStart > startSeconds - tolerance && itemEnd < endSeconds + tolerance) {
|
|
55
|
+
matches.push(item);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var removed = 0;
|
|
60
|
+
for (var m = 0; m < matches.length; m++) {
|
|
61
|
+
var target = matches[m];
|
|
62
|
+
var succeeded = false;
|
|
63
|
+
var itemCountBefore = qeTrack.numItems;
|
|
64
|
+
|
|
65
|
+
if (typeof target.rippleDelete === "function") {
|
|
66
|
+
try {
|
|
67
|
+
target.rippleDelete();
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// fall through to the numItems check below regardless
|
|
70
|
+
}
|
|
71
|
+
succeeded = qeTrack.numItems < itemCountBefore;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!succeeded && typeof target.remove === "function") {
|
|
75
|
+
// QE clip.remove()'s two boolean params are undocumented (roughly
|
|
76
|
+
// ripple/alignToVideo-shaped, per Premiere's standard-DOM equivalent) —
|
|
77
|
+
// try plausible combinations and judge success by numItems, not by
|
|
78
|
+
// assuming what either flag means.
|
|
79
|
+
var attempts = [[true, false], [true, true], [false, true], [false, false]];
|
|
80
|
+
for (var a = 0; a < attempts.length && !succeeded; a++) {
|
|
81
|
+
var countBeforeAttempt = qeTrack.numItems;
|
|
82
|
+
try {
|
|
83
|
+
target.remove(attempts[a][0], attempts[a][1]);
|
|
84
|
+
} catch (e) {
|
|
85
|
+
// fall through to the numItems check below regardless
|
|
86
|
+
}
|
|
87
|
+
succeeded = qeTrack.numItems < countBeforeAttempt;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (succeeded) {
|
|
92
|
+
removed++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (removed < matches.length) {
|
|
97
|
+
warnings.push(
|
|
98
|
+
trackLabel + ": " + (matches.length - removed) + " of " + matches.length +
|
|
99
|
+
" segment(s) in range could not be removed (rippleDelete/remove all reported no change)"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return removed;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function ppb_removeTrackIntervals(argsJson) {
|
|
107
|
+
try {
|
|
108
|
+
var args;
|
|
109
|
+
try {
|
|
110
|
+
args = JSON.parse(argsJson);
|
|
111
|
+
} catch (e) {
|
|
112
|
+
return JSON.stringify({ ok: false, error: "invalid args JSON: " + e.toString() });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof args.audioTrackIndex !== "number" || args.audioTrackIndex < 0 || Math.floor(args.audioTrackIndex) !== args.audioTrackIndex) {
|
|
116
|
+
return JSON.stringify({ ok: false, error: "audioTrackIndex must be a non-negative integer" });
|
|
117
|
+
}
|
|
118
|
+
var videoTrackIndices = args.videoTrackIndices || [];
|
|
119
|
+
if (!(videoTrackIndices instanceof Array)) {
|
|
120
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndices must be an array" });
|
|
121
|
+
}
|
|
122
|
+
for (var vi = 0; vi < videoTrackIndices.length; vi++) {
|
|
123
|
+
var vIdx = videoTrackIndices[vi];
|
|
124
|
+
if (typeof vIdx !== "number" || vIdx < 0 || Math.floor(vIdx) !== vIdx) {
|
|
125
|
+
return JSON.stringify({ ok: false, error: "videoTrackIndices must all be non-negative integers" });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!(args.intervals instanceof Array) || args.intervals.length === 0) {
|
|
129
|
+
return JSON.stringify({ ok: false, error: "intervals must be a non-empty array" });
|
|
130
|
+
}
|
|
131
|
+
var timecodeRe = /^\d{2,3}:\d{2}:\d{2}$/;
|
|
132
|
+
for (var ii = 0; ii < args.intervals.length; ii++) {
|
|
133
|
+
var iv = args.intervals[ii];
|
|
134
|
+
if (!iv || typeof iv.start !== "string" || typeof iv.end !== "string" ||
|
|
135
|
+
!timecodeRe.test(iv.start) || !timecodeRe.test(iv.end)) {
|
|
136
|
+
return JSON.stringify({ ok: false, error: "each interval must have \"start\"/\"end\" as \"MM:SS:FF\" strings (index " + ii + ")" });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!app.project) {
|
|
141
|
+
return JSON.stringify({ ok: false, error: "no project open" });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
var seq = null;
|
|
145
|
+
if (args.sequenceName && typeof args.sequenceName === "string") {
|
|
146
|
+
seq = findSequenceByName(args.sequenceName);
|
|
147
|
+
if (!seq) {
|
|
148
|
+
return JSON.stringify({ ok: false, error: "no sequence named \"" + args.sequenceName + "\" is open" });
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
seq = app.project.activeSequence;
|
|
152
|
+
if (!seq) {
|
|
153
|
+
return JSON.stringify({ ok: false, error: "no active sequence, and no sequenceName given" });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// QE DOM only ever operates on the active sequence tab — switch to it
|
|
158
|
+
// rather than erroring if the resolved sequence isn't already active.
|
|
159
|
+
if (app.project.activeSequence !== seq) {
|
|
160
|
+
app.project.activeSequence = seq;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
ensureQEEnabled();
|
|
165
|
+
} catch (e) {
|
|
166
|
+
return JSON.stringify({ ok: false, error: "app.enableQE() failed: " + e.toString() });
|
|
167
|
+
}
|
|
168
|
+
if (typeof qe === "undefined" || !qe.project) {
|
|
169
|
+
return JSON.stringify({ ok: false, error: "QE DOM not available after enableQE()" });
|
|
170
|
+
}
|
|
171
|
+
var qeSequence = qe.project.getActiveSequence();
|
|
172
|
+
if (!qeSequence) {
|
|
173
|
+
return JSON.stringify({ ok: false, error: "qe.project.getActiveSequence() returned nothing after activating the sequence" });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (args.audioTrackIndex >= qeSequence.numAudioTracks) {
|
|
177
|
+
return JSON.stringify({
|
|
178
|
+
ok: false,
|
|
179
|
+
error: "audioTrackIndex " + args.audioTrackIndex + " is out of range (sequence \"" + seq.name + "\" has " + qeSequence.numAudioTracks + " audio track(s))"
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
for (var vc = 0; vc < videoTrackIndices.length; vc++) {
|
|
183
|
+
if (videoTrackIndices[vc] >= qeSequence.numVideoTracks) {
|
|
184
|
+
return JSON.stringify({
|
|
185
|
+
ok: false,
|
|
186
|
+
error: "videoTrackIndices[" + vc + "]=" + videoTrackIndices[vc] + " is out of range (sequence \"" + seq.name + "\" has " + qeSequence.numVideoTracks + " video track(s))"
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
var fps = getSequenceFps(seq);
|
|
192
|
+
|
|
193
|
+
var parsedIntervals = [];
|
|
194
|
+
for (var pi = 0; pi < args.intervals.length; pi++) {
|
|
195
|
+
var rawInterval = args.intervals[pi];
|
|
196
|
+
var startSeconds = timecodeToSeconds(rawInterval.start, fps);
|
|
197
|
+
var endSeconds = timecodeToSeconds(rawInterval.end, fps);
|
|
198
|
+
if (endSeconds <= startSeconds) {
|
|
199
|
+
return JSON.stringify({ ok: false, error: "interval " + pi + " (\"" + rawInterval.start + "\" - \"" + rawInterval.end + "\") is empty or backwards" });
|
|
200
|
+
}
|
|
201
|
+
parsedIntervals.push({ start: rawInterval.start, end: rawInterval.end, startSeconds: startSeconds, endSeconds: endSeconds });
|
|
202
|
+
}
|
|
203
|
+
parsedIntervals.sort(function (a, b) { return a.startSeconds - b.startSeconds; });
|
|
204
|
+
for (var oi = 1; oi < parsedIntervals.length; oi++) {
|
|
205
|
+
if (parsedIntervals[oi].startSeconds < parsedIntervals[oi - 1].endSeconds) {
|
|
206
|
+
return JSON.stringify({
|
|
207
|
+
ok: false,
|
|
208
|
+
error: "intervals overlap (\"" + parsedIntervals[oi - 1].start + "\" - \"" + parsedIntervals[oi - 1].end +
|
|
209
|
+
"\" and \"" + parsedIntervals[oi].start + "\" - \"" + parsedIntervals[oi].end + "\")"
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
var tolerance = 0.5 / fps;
|
|
215
|
+
var warnings = [];
|
|
216
|
+
var totalSegmentsRemoved = 0;
|
|
217
|
+
|
|
218
|
+
// Process last-to-first: applying a cut ripples everything after it,
|
|
219
|
+
// so earlier (not-yet-processed) intervals' absolute positions stay
|
|
220
|
+
// valid until their own turn comes.
|
|
221
|
+
for (var idx = parsedIntervals.length - 1; idx >= 0; idx--) {
|
|
222
|
+
var interval = parsedIntervals[idx];
|
|
223
|
+
|
|
224
|
+
qeSequence.razor(toQeTimecode(interval.start));
|
|
225
|
+
qeSequence.razor(toQeTimecode(interval.end));
|
|
226
|
+
|
|
227
|
+
var audioTrack = qeSequence.getAudioTrackAt(args.audioTrackIndex);
|
|
228
|
+
totalSegmentsRemoved += findAndRemoveInRange(
|
|
229
|
+
audioTrack, interval.startSeconds, interval.endSeconds, tolerance, warnings, "Audio " + (args.audioTrackIndex + 1)
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
for (var vt = 0; vt < videoTrackIndices.length; vt++) {
|
|
233
|
+
var videoTrack = qeSequence.getVideoTrackAt(videoTrackIndices[vt]);
|
|
234
|
+
totalSegmentsRemoved += findAndRemoveInRange(
|
|
235
|
+
videoTrack, interval.startSeconds, interval.endSeconds, tolerance, warnings, "Video " + (videoTrackIndices[vt] + 1)
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return JSON.stringify({
|
|
241
|
+
ok: true,
|
|
242
|
+
result: {
|
|
243
|
+
sequenceName: seq.name,
|
|
244
|
+
audioTrackIndex: args.audioTrackIndex,
|
|
245
|
+
videoTrackIndices: videoTrackIndices,
|
|
246
|
+
intervalsApplied: parsedIntervals.length,
|
|
247
|
+
totalSegmentsRemoved: totalSegmentsRemoved,
|
|
248
|
+
warnings: warnings
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
} catch (e) {
|
|
252
|
+
return JSON.stringify({ ok: false, error: e.toString() });
|
|
253
|
+
}
|
|
254
|
+
}
|