premiere-cli 0.4.2__tar.gz → 0.4.3__tar.gz
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-0.4.2/src/premiere_cli.egg-info → premiere_cli-0.4.3}/PKG-INFO +1 -1
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/pyproject.toml +1 -1
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/__init__.py +1 -1
- premiere_cli-0.4.3/src/premiere_cli/add_background.py +230 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/cli.py +166 -8
- premiere_cli-0.4.3/src/premiere_cli/insert_clips.py +129 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-transition.jsx +16 -9
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-add-transitions.jsx +21 -9
- premiere_cli-0.4.3/src/premiere_cli/panel/host/commands/delete-all-markers.jsx +160 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-audio-transitions.jsx +8 -9
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-transitions.jsx +10 -12
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/overwrite-clip-at.jsx +3 -2
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/index.jsx +89 -16
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/js/main.js +2 -1
- premiere_cli-0.4.3/src/premiere_cli/sync_assets.py +158 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3/src/premiere_cli.egg-info}/PKG-INFO +1 -1
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/SOURCES.txt +8 -2
- premiere_cli-0.4.3/tests/test_add_background.py +282 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/tests/test_cli.py +99 -1
- premiere_cli-0.4.3/tests/test_insert_clips.py +149 -0
- premiere_cli-0.4.3/tests/test_sync_assets.py +180 -0
- premiere_cli-0.4.2/tests/test_desktop_driver.py +0 -41
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/LICENSE +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/README.md +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/setup.cfg +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/desktop_driver.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/desktop_overlay.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/init_project.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/log.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/notify_daemon.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/.debug +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/CSXS/manifest.xml +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/css/style.css +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-adjustment-layer.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-audio-keyframes.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-custom-metadata-field.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-keyframe.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-marker-to-project-item.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-marker.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-text-overlay.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-to-render-queue.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-to-timeline.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/adjust-audio-levels.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-audio-effect.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-effect.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-lut.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/attach-custom-property.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/auto-reframe-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-apply-effect.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-rename-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-set-clips-enabled.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/clear-item-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/clear-sequence-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-all-source-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-source-monitor.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/color-correct.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/copy-effect-values.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/copy-effects-between-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-bars-and-tone.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-bin.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-caption-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence-from-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence-from-preset.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-smart-bin.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-subclip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-subsequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/debug-qe-inspect.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/debug-qe-try-mutate.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/delete-marker.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/deselect-all-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/detach-proxy.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/duplicate-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/duplicate-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/encode-file.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/encode-project-item.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-aaf.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-fcp-xml.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-frame.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-omf.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-sequence-as-project.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/extract-audio-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/extract-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/find-items-by-media-path.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/freeze-frame.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-active-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-all-project-paths.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-bin-contents.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-adjustment-layer.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-at-playhead.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-at-position.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-links.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-markers.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-speed.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-color-label.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-color-space.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-duplicate-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-effect-properties.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-encoder-presets.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-export-file-extension.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-footage-interpretation.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-clip-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-project-overview.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-sequence-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-graphics-white-luminance.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-insertion-bin.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-item-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-keyframes.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-mogrt-component.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-next-edit-point.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-offline-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-open-projects.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-premiere-state.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-item-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-panel-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-qe-clip-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-render-queue-status.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-count.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-markers-by-type.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-source-monitor-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-source-monitor-position.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-target-tracks.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-timeline-gaps.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-timeline-summary.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-total-clip-count.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-track-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-unused-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-used-media-report.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-value-at-time.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-version-info.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-work-area.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-workspaces.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-xmp-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-ae-comps.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-fcp-xml.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-folder.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-image-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-mogrt-from-library.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-mogrt.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-sequences-from-project.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/insert-from-source.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/inspect-dom-object.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/invert-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/is-work-area-enabled.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/lift-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/link-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-audio-effects.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-effects.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-markers.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-project-items.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/lock-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/manage-proxies.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/match-frame.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-clip-to-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-items-to-bin.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-playhead-to-edit.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-playhead.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/nest-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/open-in-source.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/open-project.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/overwrite-from-source.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/play-source-monitor.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/play-timeline.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/razor-all-tracks.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/redo.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/refresh-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/relink-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-all-effects.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-effect-by-name.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-effect.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-from-timeline.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-keyframe-range.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-keyframe.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-selected-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-track-intervals.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-transition.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-bin.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-project-item.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/replace-clip-media.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/replace-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/reverse-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/ripple-delete-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/roll-edit.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/save-project-as.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/save-project.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/scene-edit-detection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/search-project-items.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-all-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-by-color.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-by-name.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-in-range.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-disabled-clips.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-project-item.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-active-project.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-active-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-all-tracks-targeted.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-anti-alias-quality.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-blend-mode.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-anchor-point.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-enabled.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-opacity.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-pan.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-position.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-properties.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-rotation.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-scale.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-speed.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-volume.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-color-label.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-color-value.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-effect-property.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-footage-interpretation.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-frame-blend.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-graphics-white-luminance.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-offline.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-start-time.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-keyframe-interpolation.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-override-frame-rate.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-override-pixel-aspect-ratio.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-poster-frame.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-project-panel-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-scale-to-frame-size.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-scale-width-height.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-sequence-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-sequence-settings.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-source-in-out.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-target-track.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-time-interpolation.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-track-mute.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-track-visibility.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-transcode-on-ingest.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-uniform-scale.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-work-area.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-workspace.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-xmp-metadata.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/slide-edit.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/slip-edit.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/split-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/stabilize-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/stop-playback.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/trim-clip.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/undo.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/unlink-selection.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/unnest-sequence.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/update-marker.jsx +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/presets/default-4k-25fps.sqpreset +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/index.html +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/js/cs-interface.js +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel_install.py +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/templates/empty-project/Adobe Premiere Pro Auto-Save/Untitled--8627e8e5-eccf-e7ea-8c87-b4de7f17596a-2026-07-10_12-30-47.prproj +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/templates/empty-project/Untitled.prproj +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/dependency_links.txt +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/entry_points.txt +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/requires.txt +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/top_level.txt +0 -0
- {premiere_cli-0.4.2 → premiere_cli-0.4.3}/tests/test_log.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: premiere-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Drive Adobe Premiere Pro from the command line: a Python CLI plus a bundled CEP bridge panel exposing Premiere's scripting APIs over local HTTP
|
|
5
5
|
License: CC-BY-SA-4.0
|
|
6
6
|
Project-URL: Repository, https://github.com/stefanwebb/premiere-cli
|
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
|
6
6
|
name = "premiere-cli"
|
|
7
7
|
# Keep in lockstep with premiere_cli.__version__ and PANEL_VERSION in
|
|
8
8
|
# src/premiere_cli/panel/js/main.js.
|
|
9
|
-
version = "0.4.
|
|
9
|
+
version = "0.4.3"
|
|
10
10
|
description = "Drive Adobe Premiere Pro from the command line: a Python CLI plus a bundled CEP bridge panel exposing Premiere's scripting APIs over local HTTP"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
license = {text = "CC-BY-SA-4.0"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""Fill spans of a timeline with a looped background clip.
|
|
2
|
+
|
|
3
|
+
Composed from existing panel commands rather than added as a new one:
|
|
4
|
+
`set-item-in-out` controls how much of the source is placed, and
|
|
5
|
+
`overwrite-clip-at` puts it on the timeline. That reuses
|
|
6
|
+
`overwrite-clip-at`'s verified placement path — including its cleanup of the
|
|
7
|
+
auto-linked audio Premiere silently drops onto an audio track — and needs no
|
|
8
|
+
panel reload.
|
|
9
|
+
|
|
10
|
+
Which spans to fill is the caller's business: pass them in a cuts-style
|
|
11
|
+
intervals file. The spans a *video project* wants (say, every motion graphic
|
|
12
|
+
with no talking head behind it) come from that project's own script metadata,
|
|
13
|
+
which this package knows nothing about.
|
|
14
|
+
|
|
15
|
+
**⚠️ A background clip WITH AN AUDIO STREAM will destroy audio underneath it.**
|
|
16
|
+
Placing video via `overwrite-clip-at` makes Premiere auto-link the source's
|
|
17
|
+
audio onto an audio track; that command removes the audio it *added*, but the
|
|
18
|
+
audio it *overwrote* is gone and undo does not work on this build. Observed
|
|
19
|
+
live: filling 9 spans with a 5s h264+aac clip silently blew 221s of holes in
|
|
20
|
+
the dialogue on A1. Before running, either strip the audio from the background
|
|
21
|
+
file, or confirm the audio tracks it would land on are empty. `--dry-run`
|
|
22
|
+
reports the plan; it cannot warn you about this, because the damage happens in
|
|
23
|
+
Premiere, not here.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from math import gcd
|
|
29
|
+
from typing import Optional
|
|
30
|
+
|
|
31
|
+
#: Anything shorter than this many frames is not worth an edit point.
|
|
32
|
+
MIN_PLACEMENT_FRAMES = 1
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def clip_intervals(
|
|
36
|
+
intervals: list[dict], start: Optional[float], end: Optional[float]
|
|
37
|
+
) -> list[dict]:
|
|
38
|
+
"""Restrict intervals to [start, end], dropping and truncating as needed."""
|
|
39
|
+
out = []
|
|
40
|
+
for interval in intervals:
|
|
41
|
+
lo, hi = interval["start"], interval["end"]
|
|
42
|
+
if start is not None:
|
|
43
|
+
lo = max(lo, start)
|
|
44
|
+
if end is not None:
|
|
45
|
+
hi = min(hi, end)
|
|
46
|
+
if hi > lo:
|
|
47
|
+
out.append({"start": lo, "end": hi})
|
|
48
|
+
return out
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def plan_fill(
|
|
52
|
+
intervals: list[dict],
|
|
53
|
+
source_duration: float,
|
|
54
|
+
fps: float,
|
|
55
|
+
source_fps: Optional[float] = None,
|
|
56
|
+
) -> list[dict]:
|
|
57
|
+
"""Plan the placements that tile each interval with the source clip.
|
|
58
|
+
|
|
59
|
+
The source repeats until the span is full and the final repeat is trimmed,
|
|
60
|
+
so a span is covered exactly — no gap, no overhang. Every start and length
|
|
61
|
+
is quantised to a whole frame: at sub-frame precision the repeats drift and
|
|
62
|
+
leave a one-frame hole between them.
|
|
63
|
+
|
|
64
|
+
When the source's frame rate differs from the sequence's, the loop length
|
|
65
|
+
must be a whole number of frames in **both** grids. Premiere trims the
|
|
66
|
+
source on the SOURCE's grid, so a length that is whole only on the
|
|
67
|
+
sequence's grid lands sub-frame on the timeline and gets floored — every
|
|
68
|
+
repeat comes out a frame short and leaves a hole. A 5.033s 30fps clip on a
|
|
69
|
+
25fps sequence did exactly that across 43 repeats. The common grid for
|
|
70
|
+
25 and 30 is 0.2s, so the loop floors to 5.0s and tiles cleanly.
|
|
71
|
+
"""
|
|
72
|
+
if source_duration <= 0:
|
|
73
|
+
raise ValueError("source_duration must be positive")
|
|
74
|
+
|
|
75
|
+
frame = 1.0 / fps
|
|
76
|
+
loop_frames = max(1, int(round(source_duration * fps)))
|
|
77
|
+
if source_fps and abs(source_fps - fps) > 1e-9:
|
|
78
|
+
# Frames of the sequence grid that are also whole frames of the source's.
|
|
79
|
+
step = int(round(fps)) // gcd(int(round(fps)), int(round(source_fps)))
|
|
80
|
+
loop_frames = max(step, (loop_frames // step) * step)
|
|
81
|
+
placements = []
|
|
82
|
+
for interval in intervals:
|
|
83
|
+
start_frame = int(round(interval["start"] * fps))
|
|
84
|
+
end_frame = int(round(interval["end"] * fps))
|
|
85
|
+
cursor = start_frame
|
|
86
|
+
while cursor < end_frame:
|
|
87
|
+
remaining = end_frame - cursor
|
|
88
|
+
length = min(loop_frames, remaining)
|
|
89
|
+
if length < MIN_PLACEMENT_FRAMES:
|
|
90
|
+
break
|
|
91
|
+
placements.append(
|
|
92
|
+
{
|
|
93
|
+
"start": round(cursor * frame, 6),
|
|
94
|
+
"out": round(length * frame, 6),
|
|
95
|
+
"trimmed": length < loop_frames,
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
cursor += length
|
|
99
|
+
return placements
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def summarise(placements: list[dict]) -> dict:
|
|
103
|
+
"""Counts a caller can report without re-deriving them."""
|
|
104
|
+
return {
|
|
105
|
+
"placements": len(placements),
|
|
106
|
+
"trimmed": sum(1 for p in placements if p["trimmed"]),
|
|
107
|
+
"total_seconds": round(sum(p["out"] for p in placements), 3),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def run(
|
|
112
|
+
submit,
|
|
113
|
+
sequence_name: Optional[str],
|
|
114
|
+
track_index: int,
|
|
115
|
+
item_node_id: Optional[str],
|
|
116
|
+
item_name: Optional[str],
|
|
117
|
+
intervals: list[dict],
|
|
118
|
+
start_seconds: Optional[float],
|
|
119
|
+
end_seconds: Optional[float],
|
|
120
|
+
source_duration_seconds: Optional[float],
|
|
121
|
+
fps: Optional[float],
|
|
122
|
+
dry_run: bool,
|
|
123
|
+
) -> dict:
|
|
124
|
+
"""Resolve the source clip, plan the fill, and place it.
|
|
125
|
+
|
|
126
|
+
`submit` is the panel client (command, args) -> response dict, injected so
|
|
127
|
+
this is testable against a fake panel.
|
|
128
|
+
"""
|
|
129
|
+
# --- resolve the source item ------------------------------------------
|
|
130
|
+
node_id = item_node_id
|
|
131
|
+
if node_id is None:
|
|
132
|
+
found = submit("search-project-items", {"nameContains": item_name})
|
|
133
|
+
if not found.get("ok"):
|
|
134
|
+
return {"ok": False, "error": f"could not search for {item_name!r}: {found.get('error')}"}
|
|
135
|
+
matches = [
|
|
136
|
+
i for i in (found["result"].get("items") or [])
|
|
137
|
+
if i.get("name") == item_name and not i.get("isSequence")
|
|
138
|
+
]
|
|
139
|
+
if not matches:
|
|
140
|
+
return {"ok": False, "error": f"no project item named {item_name!r}"}
|
|
141
|
+
if len(matches) > 1:
|
|
142
|
+
return {
|
|
143
|
+
"ok": False,
|
|
144
|
+
"error": f"{len(matches)} project items are named {item_name!r} — pass --item-node-id",
|
|
145
|
+
}
|
|
146
|
+
node_id = matches[0]["nodeId"]
|
|
147
|
+
|
|
148
|
+
info = submit("get-project-item-info", {"nodeId": node_id})
|
|
149
|
+
if not info.get("ok"):
|
|
150
|
+
return {"ok": False, "error": f"could not read the source item: {info.get('error')}"}
|
|
151
|
+
item = info["result"]
|
|
152
|
+
original_in = item.get("inPointSeconds") or 0.0
|
|
153
|
+
original_out = item.get("outPointSeconds")
|
|
154
|
+
# Premiere trims on the source's own frame grid — see plan_fill.
|
|
155
|
+
source_fps = item.get("frameRate")
|
|
156
|
+
|
|
157
|
+
duration = source_duration_seconds
|
|
158
|
+
if duration is None:
|
|
159
|
+
if original_out is None:
|
|
160
|
+
return {
|
|
161
|
+
"ok": False,
|
|
162
|
+
"error": "the source item reports no out point — pass --source-duration-seconds",
|
|
163
|
+
}
|
|
164
|
+
duration = original_out - original_in
|
|
165
|
+
if duration <= 0:
|
|
166
|
+
return {"ok": False, "error": f"source duration is not positive ({duration})"}
|
|
167
|
+
|
|
168
|
+
# --- frame grid: the SEQUENCE's, not the source's ---------------------
|
|
169
|
+
if fps is None:
|
|
170
|
+
project = submit("get-project-info", {})
|
|
171
|
+
if not project.get("ok"):
|
|
172
|
+
return {"ok": False, "error": f"could not read the project: {project.get('error')}"}
|
|
173
|
+
sequences = project["result"].get("sequences") or []
|
|
174
|
+
target = sequence_name or (sequences[0]["name"] if sequences else None)
|
|
175
|
+
match = next((s for s in sequences if s["name"] == target), None)
|
|
176
|
+
if match is None:
|
|
177
|
+
return {"ok": False, "error": f"no sequence named {target!r} is open"}
|
|
178
|
+
fps = float(match["frameRate"])
|
|
179
|
+
|
|
180
|
+
spans = clip_intervals(intervals, start_seconds, end_seconds)
|
|
181
|
+
placements = plan_fill(spans, duration, fps, source_fps=source_fps)
|
|
182
|
+
plan = {
|
|
183
|
+
"sequenceName": sequence_name,
|
|
184
|
+
"trackIndex": track_index,
|
|
185
|
+
"itemNodeId": node_id,
|
|
186
|
+
"sourceDurationSeconds": round(duration, 3),
|
|
187
|
+
"fps": fps,
|
|
188
|
+
"sourceFps": source_fps,
|
|
189
|
+
"spans": len(spans),
|
|
190
|
+
**summarise(placements),
|
|
191
|
+
}
|
|
192
|
+
if dry_run:
|
|
193
|
+
return {"ok": True, "result": {**plan, "dryRun": True, "placementList": placements}}
|
|
194
|
+
|
|
195
|
+
# --- place ------------------------------------------------------------
|
|
196
|
+
placed, failures = 0, []
|
|
197
|
+
for p in placements:
|
|
198
|
+
trim = submit(
|
|
199
|
+
"set-item-in-out",
|
|
200
|
+
{"nodeId": node_id, "inSeconds": original_in,
|
|
201
|
+
"outSeconds": round(original_in + p["out"], 6), "mediaType": 1},
|
|
202
|
+
)
|
|
203
|
+
if not trim.get("ok"):
|
|
204
|
+
failures.append({"start": p["start"], "stage": "set-item-in-out", "error": trim.get("error")})
|
|
205
|
+
continue
|
|
206
|
+
put = submit(
|
|
207
|
+
"overwrite-clip-at",
|
|
208
|
+
{"itemNodeId": node_id, "trackType": "video", "trackIndex": track_index,
|
|
209
|
+
"startSeconds": p["start"], "sequenceName": sequence_name},
|
|
210
|
+
)
|
|
211
|
+
if put.get("ok"):
|
|
212
|
+
placed += 1
|
|
213
|
+
else:
|
|
214
|
+
failures.append({"start": p["start"], "stage": "overwrite-clip-at", "error": put.get("error")})
|
|
215
|
+
|
|
216
|
+
# Leave the source item as we found it — a trimmed out point would silently
|
|
217
|
+
# shorten every later use of this clip.
|
|
218
|
+
restored = True
|
|
219
|
+
if original_out is not None:
|
|
220
|
+
restore = submit(
|
|
221
|
+
"set-item-in-out",
|
|
222
|
+
{"nodeId": node_id, "inSeconds": original_in, "outSeconds": original_out, "mediaType": 1},
|
|
223
|
+
)
|
|
224
|
+
restored = bool(restore.get("ok"))
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
"ok": not failures,
|
|
228
|
+
"result": {**plan, "placed": placed, "sourceInOutRestored": restored,
|
|
229
|
+
"failureCount": len(failures), "failures": failures[:10]},
|
|
230
|
+
}
|
|
@@ -73,6 +73,12 @@ def _parse_intervals_file(path: str) -> list:
|
|
|
73
73
|
return intervals
|
|
74
74
|
|
|
75
75
|
|
|
76
|
+
def _timecode_to_seconds(timecode: str, fps: float) -> float:
|
|
77
|
+
"""Convert an "MM:SS:FF" timecode to seconds at `fps`."""
|
|
78
|
+
minutes, seconds, frames = (int(part) for part in timecode.split(":"))
|
|
79
|
+
return minutes * 60 + seconds + frames / fps
|
|
80
|
+
|
|
81
|
+
|
|
76
82
|
def submit_command(command: str, args: dict | None = None, port: int = DEFAULT_PORT) -> dict:
|
|
77
83
|
"""POST a command to the Premiere Bridge panel's /command endpoint.
|
|
78
84
|
|
|
@@ -769,6 +775,19 @@ def main() -> None:
|
|
|
769
775
|
"--item-name", help="Exact name of a PROJECT ITEM to delete the marker from instead of a sequence"
|
|
770
776
|
)
|
|
771
777
|
|
|
778
|
+
delete_all_markers_parser = subparsers.add_parser(
|
|
779
|
+
"delete-all-markers", help="Delete every marker on a sequence or project item"
|
|
780
|
+
)
|
|
781
|
+
delete_all_markers_parser.add_argument(
|
|
782
|
+
"--sequence-name", help="Name of the sequence to clear markers from (default: the currently active sequence)"
|
|
783
|
+
)
|
|
784
|
+
delete_all_markers_parser.add_argument(
|
|
785
|
+
"--node-id", help="Node ID of a PROJECT ITEM to clear markers from instead of a sequence"
|
|
786
|
+
)
|
|
787
|
+
delete_all_markers_parser.add_argument(
|
|
788
|
+
"--item-name", help="Exact name of a PROJECT ITEM to clear markers from instead of a sequence"
|
|
789
|
+
)
|
|
790
|
+
|
|
772
791
|
add_marker_to_item_parser = subparsers.add_parser(
|
|
773
792
|
"add-marker-to-project-item", help="Add a source marker to a project item"
|
|
774
793
|
)
|
|
@@ -1380,30 +1399,96 @@ def main() -> None:
|
|
|
1380
1399
|
set_color_value_parser.add_argument("--blue", type=float, required=True, help="Blue channel, 0-255")
|
|
1381
1400
|
|
|
1382
1401
|
add_transition_parser = subparsers.add_parser(
|
|
1383
|
-
"add-transition", help="Add a video transition to a clip's start or end (QE DOM, disputed signature)"
|
|
1402
|
+
"add-transition", help="Add a video or audio transition to a clip's start or end (QE DOM, disputed signature)"
|
|
1384
1403
|
)
|
|
1385
|
-
add_transition_parser.add_argument("--track-type", required=True, choices=["video"], help="Track type the clip is on
|
|
1386
|
-
add_transition_parser.add_argument("--track-index", type=int, required=True, help="0-based index of the
|
|
1404
|
+
add_transition_parser.add_argument("--track-type", required=True, choices=["video", "audio"], help="Track type the clip is on")
|
|
1405
|
+
add_transition_parser.add_argument("--track-index", type=int, required=True, help="0-based index of the track")
|
|
1387
1406
|
add_transition_parser.add_argument("--clip-index", type=int, required=True, help="0-based index of the clip on that track")
|
|
1388
1407
|
add_transition_parser.add_argument("--at-end", required=True, choices=["true", "false"], help="true = apply at the clip's end, false = at its start")
|
|
1389
|
-
add_transition_parser.add_argument("--transition-name", help="Transition name, e.g. 'Cross Dissolve' (omit for the default
|
|
1408
|
+
add_transition_parser.add_argument("--transition-name", help="Transition name, e.g. 'Cross Dissolve' (video) or 'Constant Power' (audio); omit for the track type's default")
|
|
1390
1409
|
add_transition_parser.add_argument("--duration-seconds", type=float, help="Transition duration in seconds (default: 1.0)")
|
|
1391
1410
|
add_transition_parser.add_argument(
|
|
1392
1411
|
"--sequence-name", help="Name of the sequence to edit (default: the currently active sequence)"
|
|
1393
1412
|
)
|
|
1394
1413
|
|
|
1395
1414
|
batch_add_transitions_parser = subparsers.add_parser(
|
|
1396
|
-
"batch-add-transitions", help="Add the same transition to every clip on one video track (capped at 100)"
|
|
1415
|
+
"batch-add-transitions", help="Add the same transition to every clip on one video or audio track (capped at 100)"
|
|
1397
1416
|
)
|
|
1398
|
-
batch_add_transitions_parser.add_argument("--track-type", choices=["video"], help="Track type (
|
|
1399
|
-
batch_add_transitions_parser.add_argument("--track-index", type=int, help="0-based index of the
|
|
1417
|
+
batch_add_transitions_parser.add_argument("--track-type", choices=["video", "audio"], help="Track type (default: video)")
|
|
1418
|
+
batch_add_transitions_parser.add_argument("--track-index", type=int, help="0-based index of the track (default: 0)")
|
|
1400
1419
|
batch_add_transitions_parser.add_argument("--at-end", choices=["true", "false"], help="true = apply at each clip's end (default), false = at its start")
|
|
1401
|
-
batch_add_transitions_parser.add_argument("--transition-name", help="Transition name, e.g. 'Cross Dissolve' (omit for the default
|
|
1420
|
+
batch_add_transitions_parser.add_argument("--transition-name", help="Transition name, e.g. 'Cross Dissolve' (video) or 'Constant Power' (audio); omit for the track type's default")
|
|
1402
1421
|
batch_add_transitions_parser.add_argument("--duration-seconds", type=float, help="Transition duration in seconds (default: 1.0)")
|
|
1403
1422
|
batch_add_transitions_parser.add_argument(
|
|
1404
1423
|
"--sequence-name", help="Name of the sequence to edit (default: the currently active sequence)"
|
|
1405
1424
|
)
|
|
1406
1425
|
|
|
1426
|
+
sync_assets_parser = subparsers.add_parser(
|
|
1427
|
+
"sync-assets",
|
|
1428
|
+
help="Import every media file under an assets/ tree into matching bins, relinking any item that already has the name",
|
|
1429
|
+
)
|
|
1430
|
+
sync_assets_parser.add_argument(
|
|
1431
|
+
"--assets-dir", required=True,
|
|
1432
|
+
help="the assets/ directory to sync (bins mirror its subdirectories)",
|
|
1433
|
+
)
|
|
1434
|
+
sync_assets_parser.add_argument(
|
|
1435
|
+
"--dry-run", action="store_true", help="report the plan without changing the project"
|
|
1436
|
+
)
|
|
1437
|
+
|
|
1438
|
+
insert_clips_parser = subparsers.add_parser(
|
|
1439
|
+
"insert-clips",
|
|
1440
|
+
help="Place a bin's clips whose names start with an MM-SS-FF timecode onto a track at that time",
|
|
1441
|
+
)
|
|
1442
|
+
insert_clips_parser.add_argument("--bin-path", required=True, help="'/'-separated bin to read")
|
|
1443
|
+
insert_clips_parser.add_argument(
|
|
1444
|
+
"--track-type", choices=["video", "audio"], default="video", help="Track type (default: video)"
|
|
1445
|
+
)
|
|
1446
|
+
insert_clips_parser.add_argument("--track-index", type=int, required=True, help="0-based track index")
|
|
1447
|
+
insert_clips_parser.add_argument(
|
|
1448
|
+
"--fps", type=float, help="Frame rate the timecodes are in (default: the sequence's)"
|
|
1449
|
+
)
|
|
1450
|
+
insert_clips_parser.add_argument(
|
|
1451
|
+
"--sequence-name", help="Name of the sequence to edit (default: the currently active sequence)"
|
|
1452
|
+
)
|
|
1453
|
+
insert_clips_parser.add_argument(
|
|
1454
|
+
"--dry-run", action="store_true", help="report the plan without changing the timeline"
|
|
1455
|
+
)
|
|
1456
|
+
|
|
1457
|
+
add_background_parser = subparsers.add_parser(
|
|
1458
|
+
"add-background",
|
|
1459
|
+
help="Fill given time spans of a video track with a looped background clip, trimming the last repeat",
|
|
1460
|
+
)
|
|
1461
|
+
add_background_parser.add_argument(
|
|
1462
|
+
"--sequence-name", help="Name of the sequence to edit (default: the currently active sequence)"
|
|
1463
|
+
)
|
|
1464
|
+
add_background_parser.add_argument(
|
|
1465
|
+
"--track-index", type=int, required=True, help="0-based index of the video track to fill"
|
|
1466
|
+
)
|
|
1467
|
+
bg_source = add_background_parser.add_mutually_exclusive_group(required=True)
|
|
1468
|
+
bg_source.add_argument("--item-node-id", help="Node ID of the background project item")
|
|
1469
|
+
bg_source.add_argument("--item-name", help="Name of the background project item (must be unique)")
|
|
1470
|
+
add_background_parser.add_argument(
|
|
1471
|
+
"--intervals-file", required=True,
|
|
1472
|
+
help="Cuts-style file of spans to fill, one 'MM:SS:FF - MM:SS:FF' per line. "
|
|
1473
|
+
"Which spans a video needs is the caller's business — see the command's docs.",
|
|
1474
|
+
)
|
|
1475
|
+
add_background_parser.add_argument(
|
|
1476
|
+
"--start-seconds", type=float, help="Only fill at or after this time"
|
|
1477
|
+
)
|
|
1478
|
+
add_background_parser.add_argument(
|
|
1479
|
+
"--end-seconds", type=float, help="Only fill up to this time"
|
|
1480
|
+
)
|
|
1481
|
+
add_background_parser.add_argument(
|
|
1482
|
+
"--source-duration-seconds", type=float,
|
|
1483
|
+
help="Loop length to use (default: the source item's own in/out span)",
|
|
1484
|
+
)
|
|
1485
|
+
add_background_parser.add_argument(
|
|
1486
|
+
"--fps", type=float, help="Frame grid to quantise to (default: the sequence's frame rate)"
|
|
1487
|
+
)
|
|
1488
|
+
add_background_parser.add_argument(
|
|
1489
|
+
"--dry-run", action="store_true", help="Report the planned placements without changing the timeline"
|
|
1490
|
+
)
|
|
1491
|
+
|
|
1407
1492
|
remove_transition_parser = subparsers.add_parser(
|
|
1408
1493
|
"remove-transition", help="Remove a transition from a track (standard DOM, disputed remove() arity); lists transitions if the index is out of range"
|
|
1409
1494
|
)
|
|
@@ -2267,6 +2352,72 @@ def main() -> None:
|
|
|
2267
2352
|
from premiere_cli import init_project
|
|
2268
2353
|
|
|
2269
2354
|
sys.exit(init_project.init_project(args.project_name, args.series, args.base_dir))
|
|
2355
|
+
if args.subcommand == "sync-assets":
|
|
2356
|
+
from premiere_cli import sync_assets as sync_assets_mod
|
|
2357
|
+
|
|
2358
|
+
response = sync_assets_mod.run(
|
|
2359
|
+
lambda command, command_args: submit_command(command, command_args, port=args.port),
|
|
2360
|
+
args.assets_dir, dry_run=args.dry_run,
|
|
2361
|
+
)
|
|
2362
|
+
print(json.dumps(response, indent=2))
|
|
2363
|
+
sys.exit(0 if response.get("ok") else 1)
|
|
2364
|
+
if args.subcommand == "insert-clips":
|
|
2365
|
+
from premiere_cli import insert_clips as insert_clips_mod
|
|
2366
|
+
|
|
2367
|
+
response = insert_clips_mod.run(
|
|
2368
|
+
lambda command, command_args: submit_command(command, command_args, port=args.port),
|
|
2369
|
+
sequence_name=args.sequence_name,
|
|
2370
|
+
bin_path=args.bin_path,
|
|
2371
|
+
track_type=args.track_type,
|
|
2372
|
+
track_index=args.track_index,
|
|
2373
|
+
fps=args.fps,
|
|
2374
|
+
dry_run=args.dry_run,
|
|
2375
|
+
)
|
|
2376
|
+
print(json.dumps(response, indent=2))
|
|
2377
|
+
sys.exit(0 if response.get("ok") else 1)
|
|
2378
|
+
if args.subcommand == "add-background":
|
|
2379
|
+
from premiere_cli import add_background as add_background_mod
|
|
2380
|
+
|
|
2381
|
+
try:
|
|
2382
|
+
spans = _parse_intervals_file(args.intervals_file)
|
|
2383
|
+
except (OSError, ValueError) as exc:
|
|
2384
|
+
print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)
|
|
2385
|
+
sys.exit(1)
|
|
2386
|
+
fps_for_parse = args.fps
|
|
2387
|
+
if fps_for_parse is None:
|
|
2388
|
+
probe = submit_command("get-project-info", {}, port=args.port)
|
|
2389
|
+
if not probe.get("ok"):
|
|
2390
|
+
print(json.dumps(probe), file=sys.stderr)
|
|
2391
|
+
sys.exit(1)
|
|
2392
|
+
sequences = probe["result"].get("sequences") or []
|
|
2393
|
+
target = args.sequence_name or (sequences[0]["name"] if sequences else None)
|
|
2394
|
+
match = next((sq for sq in sequences if sq["name"] == target), None)
|
|
2395
|
+
if match is None:
|
|
2396
|
+
print(json.dumps({"ok": False, "error": f"no sequence named {target!r} is open"}), file=sys.stderr)
|
|
2397
|
+
sys.exit(1)
|
|
2398
|
+
fps_for_parse = float(match["frameRate"])
|
|
2399
|
+
seconds = [
|
|
2400
|
+
{
|
|
2401
|
+
"start": _timecode_to_seconds(sp["start"], fps_for_parse),
|
|
2402
|
+
"end": _timecode_to_seconds(sp["end"], fps_for_parse),
|
|
2403
|
+
}
|
|
2404
|
+
for sp in spans
|
|
2405
|
+
]
|
|
2406
|
+
response = add_background_mod.run(
|
|
2407
|
+
lambda command, command_args: submit_command(command, command_args, port=args.port),
|
|
2408
|
+
sequence_name=args.sequence_name,
|
|
2409
|
+
track_index=args.track_index,
|
|
2410
|
+
item_node_id=args.item_node_id,
|
|
2411
|
+
item_name=args.item_name,
|
|
2412
|
+
intervals=seconds,
|
|
2413
|
+
start_seconds=args.start_seconds,
|
|
2414
|
+
end_seconds=args.end_seconds,
|
|
2415
|
+
source_duration_seconds=args.source_duration_seconds,
|
|
2416
|
+
fps=fps_for_parse,
|
|
2417
|
+
dry_run=args.dry_run,
|
|
2418
|
+
)
|
|
2419
|
+
print(json.dumps(response, indent=2))
|
|
2420
|
+
sys.exit(0 if response.get("ok") else 1)
|
|
2270
2421
|
if args.subcommand == "desktop-take-screenshot":
|
|
2271
2422
|
desktop_driver = _load_desktop_driver(args.subcommand)
|
|
2272
2423
|
sys.exit(desktop_driver.take_screenshot(args.output_path, port=args.port))
|
|
@@ -2538,6 +2689,13 @@ def main() -> None:
|
|
|
2538
2689
|
"itemName": args.item_name,
|
|
2539
2690
|
}
|
|
2540
2691
|
command_args = {k: v for k, v in command_args.items() if v is not None}
|
|
2692
|
+
elif args.subcommand == "delete-all-markers":
|
|
2693
|
+
command_args = {
|
|
2694
|
+
"sequenceName": args.sequence_name,
|
|
2695
|
+
"nodeId": args.node_id,
|
|
2696
|
+
"itemName": args.item_name,
|
|
2697
|
+
}
|
|
2698
|
+
command_args = {k: v for k, v in command_args.items() if v is not None}
|
|
2541
2699
|
elif args.subcommand == "add-marker-to-project-item":
|
|
2542
2700
|
if not args.node_id and not args.name:
|
|
2543
2701
|
parser.error("at least one of --node-id, --name is required")
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Place already-imported clips whose names begin with their insertion time.
|
|
2
|
+
|
|
3
|
+
A delivered motion graphic is named ``MM-SS-FF - <type> - <description>.mov``,
|
|
4
|
+
where the leading field is where it belongs on the timeline. This reads one
|
|
5
|
+
bin, takes every item whose name starts with such a timecode, and overwrites it
|
|
6
|
+
onto the given track at that time. Items without a leading timecode are skipped
|
|
7
|
+
and named in the report rather than guessed at.
|
|
8
|
+
|
|
9
|
+
Composed from existing panel commands (``get-bin-contents``,
|
|
10
|
+
``overwrite-clip-at``), so it needs no panel reload.
|
|
11
|
+
|
|
12
|
+
**A source with an audio stream will destroy audio underneath it.** Premiere
|
|
13
|
+
auto-links a source's audio onto A1 whenever its video is placed, and the
|
|
14
|
+
overwrite takes whatever was there; `-1` does not suppress it on PPro 2026 (see
|
|
15
|
+
PREMIERE_API_NOTES.md). This command therefore snapshots the audio tracks before
|
|
16
|
+
and after and reports if their clip counts changed — it cannot prevent the
|
|
17
|
+
damage, only tell you it happened.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import re
|
|
23
|
+
from typing import Optional
|
|
24
|
+
|
|
25
|
+
#: MM-SS-FF at the very start of the name, then a separator.
|
|
26
|
+
_TIMECODE_RE = re.compile(r"^(\d{2})-(\d{2})-(\d{2})(?=[\s._-]|$)")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def parse_leading_timecode(name: str, fps: float) -> Optional[float]:
|
|
30
|
+
"""Seconds for a name beginning ``MM-SS-FF``, or None if it does not.
|
|
31
|
+
|
|
32
|
+
A frame field at or beyond `fps` is rejected rather than folded into the
|
|
33
|
+
next second: it means the name was not written against this sequence, and
|
|
34
|
+
silently placing the clip a second late is worse than skipping it.
|
|
35
|
+
"""
|
|
36
|
+
match = _TIMECODE_RE.match(name)
|
|
37
|
+
if not match:
|
|
38
|
+
return None
|
|
39
|
+
minutes, seconds, frames = (int(g) for g in match.groups())
|
|
40
|
+
if frames >= round(fps) or seconds >= 60:
|
|
41
|
+
return None
|
|
42
|
+
return minutes * 60 + seconds + frames / fps
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def plan_inserts(items: list[dict], fps: float) -> tuple[list[dict], list[str]]:
|
|
46
|
+
"""Split a bin's items into a time-ordered placement plan and the skipped."""
|
|
47
|
+
plan, skipped = [], []
|
|
48
|
+
for item in items:
|
|
49
|
+
name = item.get("name") or ""
|
|
50
|
+
at = parse_leading_timecode(name, fps)
|
|
51
|
+
if at is None:
|
|
52
|
+
skipped.append(name)
|
|
53
|
+
continue
|
|
54
|
+
plan.append({"name": name, "nodeId": item.get("nodeId"), "startSeconds": round(at, 6)})
|
|
55
|
+
plan.sort(key=lambda p: p["startSeconds"])
|
|
56
|
+
return plan, skipped
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _audio_snapshot(submit, sequence_name: Optional[str]) -> Optional[list[int]]:
|
|
60
|
+
args = {"sequenceName": sequence_name} if sequence_name else {}
|
|
61
|
+
response = submit("get-timeline-summary", args)
|
|
62
|
+
if not response.get("ok"):
|
|
63
|
+
return None
|
|
64
|
+
return [t.get("clipCount") for t in (response["result"].get("audioTracks") or [])]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def run(
|
|
68
|
+
submit,
|
|
69
|
+
sequence_name: Optional[str],
|
|
70
|
+
bin_path: str,
|
|
71
|
+
track_type: str,
|
|
72
|
+
track_index: int,
|
|
73
|
+
fps: Optional[float],
|
|
74
|
+
dry_run: bool,
|
|
75
|
+
) -> dict:
|
|
76
|
+
"""Read `bin_path` and place its timestamped clips onto the track."""
|
|
77
|
+
if fps is None:
|
|
78
|
+
project = submit("get-project-info", {})
|
|
79
|
+
if not project.get("ok"):
|
|
80
|
+
return {"ok": False, "error": f"could not read the project: {project.get('error')}"}
|
|
81
|
+
sequences = project["result"].get("sequences") or []
|
|
82
|
+
target = sequence_name or (sequences[0]["name"] if sequences else None)
|
|
83
|
+
match = next((s for s in sequences if s["name"] == target), None)
|
|
84
|
+
if match is None:
|
|
85
|
+
return {"ok": False, "error": f"no sequence named {target!r} is open"}
|
|
86
|
+
fps = float(match["frameRate"])
|
|
87
|
+
|
|
88
|
+
contents = submit("get-bin-contents", {"binPath": bin_path})
|
|
89
|
+
if not contents.get("ok"):
|
|
90
|
+
return {"ok": False, "error": f"could not read bin {bin_path!r}: {contents.get('error')}"}
|
|
91
|
+
result = contents.get("result") or {}
|
|
92
|
+
items = result if isinstance(result, list) else result.get("items") or []
|
|
93
|
+
items = [i for i in items if isinstance(i, dict) and i.get("type") != "BIN"]
|
|
94
|
+
|
|
95
|
+
plan, skipped = plan_inserts(items, fps)
|
|
96
|
+
summary = {
|
|
97
|
+
"sequenceName": sequence_name, "binPath": bin_path, "trackType": track_type,
|
|
98
|
+
"trackIndex": track_index, "fps": fps, "found": len(items),
|
|
99
|
+
"timestamped": len(plan), "skipped": skipped,
|
|
100
|
+
}
|
|
101
|
+
if dry_run:
|
|
102
|
+
return {"ok": True, "result": {**summary, "dryRun": True, "plan": plan}}
|
|
103
|
+
|
|
104
|
+
before = _audio_snapshot(submit, sequence_name)
|
|
105
|
+
placed, failures = 0, []
|
|
106
|
+
for entry in plan:
|
|
107
|
+
response = submit("overwrite-clip-at", {
|
|
108
|
+
"itemNodeId": entry["nodeId"], "trackType": track_type,
|
|
109
|
+
"trackIndex": track_index, "startSeconds": entry["startSeconds"],
|
|
110
|
+
"sequenceName": sequence_name,
|
|
111
|
+
})
|
|
112
|
+
if response.get("ok"):
|
|
113
|
+
placed += 1
|
|
114
|
+
else:
|
|
115
|
+
failures.append({"name": entry["name"], "startSeconds": entry["startSeconds"],
|
|
116
|
+
"error": response.get("error")})
|
|
117
|
+
after = _audio_snapshot(submit, sequence_name)
|
|
118
|
+
|
|
119
|
+
changed = None
|
|
120
|
+
if before is not None and after is not None:
|
|
121
|
+
changed = before != after
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
"ok": not failures,
|
|
125
|
+
"result": {**summary, "placed": placed,
|
|
126
|
+
"audioTracksBefore": before, "audioTracksAfter": after,
|
|
127
|
+
"audioTracksChanged": changed,
|
|
128
|
+
"failureCount": len(failures), "failures": failures[:10]},
|
|
129
|
+
}
|