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.
Files changed (268) hide show
  1. {premiere_cli-0.4.2/src/premiere_cli.egg-info → premiere_cli-0.4.3}/PKG-INFO +1 -1
  2. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/pyproject.toml +1 -1
  3. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/__init__.py +1 -1
  4. premiere_cli-0.4.3/src/premiere_cli/add_background.py +230 -0
  5. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/cli.py +166 -8
  6. premiere_cli-0.4.3/src/premiere_cli/insert_clips.py +129 -0
  7. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-transition.jsx +16 -9
  8. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-add-transitions.jsx +21 -9
  9. premiere_cli-0.4.3/src/premiere_cli/panel/host/commands/delete-all-markers.jsx +160 -0
  10. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-audio-transitions.jsx +8 -9
  11. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-transitions.jsx +10 -12
  12. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/overwrite-clip-at.jsx +3 -2
  13. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/index.jsx +89 -16
  14. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/js/main.js +2 -1
  15. premiere_cli-0.4.3/src/premiere_cli/sync_assets.py +158 -0
  16. {premiere_cli-0.4.2 → premiere_cli-0.4.3/src/premiere_cli.egg-info}/PKG-INFO +1 -1
  17. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/SOURCES.txt +8 -2
  18. premiere_cli-0.4.3/tests/test_add_background.py +282 -0
  19. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/tests/test_cli.py +99 -1
  20. premiere_cli-0.4.3/tests/test_insert_clips.py +149 -0
  21. premiere_cli-0.4.3/tests/test_sync_assets.py +180 -0
  22. premiere_cli-0.4.2/tests/test_desktop_driver.py +0 -41
  23. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/LICENSE +0 -0
  24. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/README.md +0 -0
  25. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/setup.cfg +0 -0
  26. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/desktop_driver.py +0 -0
  27. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/desktop_overlay.py +0 -0
  28. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/init_project.py +0 -0
  29. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/log.py +0 -0
  30. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/notify_daemon.py +0 -0
  31. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/.debug +0 -0
  32. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/CSXS/manifest.xml +0 -0
  33. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/css/style.css +0 -0
  34. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-adjustment-layer.jsx +0 -0
  35. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-audio-keyframes.jsx +0 -0
  36. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-custom-metadata-field.jsx +0 -0
  37. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-keyframe.jsx +0 -0
  38. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-marker-to-project-item.jsx +0 -0
  39. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-marker.jsx +0 -0
  40. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-text-overlay.jsx +0 -0
  41. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-to-render-queue.jsx +0 -0
  42. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-to-timeline.jsx +0 -0
  43. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/add-track.jsx +0 -0
  44. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/adjust-audio-levels.jsx +0 -0
  45. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-audio-effect.jsx +0 -0
  46. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-effect.jsx +0 -0
  47. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/apply-lut.jsx +0 -0
  48. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/attach-custom-property.jsx +0 -0
  49. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/auto-reframe-sequence.jsx +0 -0
  50. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-apply-effect.jsx +0 -0
  51. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-rename-clips.jsx +0 -0
  52. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/batch-set-clips-enabled.jsx +0 -0
  53. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/clear-item-in-out.jsx +0 -0
  54. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/clear-sequence-in-out.jsx +0 -0
  55. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-all-source-clips.jsx +0 -0
  56. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-sequence.jsx +0 -0
  57. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/close-source-monitor.jsx +0 -0
  58. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/color-correct.jsx +0 -0
  59. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/copy-effect-values.jsx +0 -0
  60. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/copy-effects-between-clips.jsx +0 -0
  61. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-bars-and-tone.jsx +0 -0
  62. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-bin.jsx +0 -0
  63. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-caption-track.jsx +0 -0
  64. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence-from-clips.jsx +0 -0
  65. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence-from-preset.jsx +0 -0
  66. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-sequence.jsx +0 -0
  67. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-smart-bin.jsx +0 -0
  68. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-subclip.jsx +0 -0
  69. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/create-subsequence.jsx +0 -0
  70. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/debug-qe-inspect.jsx +0 -0
  71. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/debug-qe-try-mutate.jsx +0 -0
  72. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/delete-marker.jsx +0 -0
  73. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/deselect-all-clips.jsx +0 -0
  74. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/detach-proxy.jsx +0 -0
  75. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/duplicate-clip.jsx +0 -0
  76. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/duplicate-sequence.jsx +0 -0
  77. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/encode-file.jsx +0 -0
  78. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/encode-project-item.jsx +0 -0
  79. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-aaf.jsx +0 -0
  80. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-fcp-xml.jsx +0 -0
  81. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-frame.jsx +0 -0
  82. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-omf.jsx +0 -0
  83. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-sequence-as-project.jsx +0 -0
  84. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/export-sequence.jsx +0 -0
  85. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/extract-audio-track.jsx +0 -0
  86. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/extract-selection.jsx +0 -0
  87. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/find-items-by-media-path.jsx +0 -0
  88. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/freeze-frame.jsx +0 -0
  89. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-active-sequence.jsx +0 -0
  90. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-all-project-paths.jsx +0 -0
  91. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-bin-contents.jsx +0 -0
  92. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-adjustment-layer.jsx +0 -0
  93. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-at-playhead.jsx +0 -0
  94. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-at-position.jsx +0 -0
  95. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-links.jsx +0 -0
  96. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-markers.jsx +0 -0
  97. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-clip-speed.jsx +0 -0
  98. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-color-label.jsx +0 -0
  99. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-color-space.jsx +0 -0
  100. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-duplicate-media.jsx +0 -0
  101. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-effect-properties.jsx +0 -0
  102. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-encoder-presets.jsx +0 -0
  103. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-export-file-extension.jsx +0 -0
  104. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-footage-interpretation.jsx +0 -0
  105. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-clip-info.jsx +0 -0
  106. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-project-overview.jsx +0 -0
  107. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-full-sequence-info.jsx +0 -0
  108. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-graphics-white-luminance.jsx +0 -0
  109. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-insertion-bin.jsx +0 -0
  110. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-item-metadata.jsx +0 -0
  111. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-keyframes.jsx +0 -0
  112. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-mogrt-component.jsx +0 -0
  113. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-next-edit-point.jsx +0 -0
  114. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-offline-media.jsx +0 -0
  115. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-open-projects.jsx +0 -0
  116. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-premiere-state.jsx +0 -0
  117. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-info.jsx +0 -0
  118. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-item-info.jsx +0 -0
  119. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-project-panel-metadata.jsx +0 -0
  120. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-qe-clip-info.jsx +0 -0
  121. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-render-queue-status.jsx +0 -0
  122. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-count.jsx +0 -0
  123. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-in-out.jsx +0 -0
  124. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-sequence-markers-by-type.jsx +0 -0
  125. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-source-monitor-info.jsx +0 -0
  126. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-source-monitor-position.jsx +0 -0
  127. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-target-tracks.jsx +0 -0
  128. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-timeline-gaps.jsx +0 -0
  129. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-timeline-summary.jsx +0 -0
  130. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-total-clip-count.jsx +0 -0
  131. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-track-info.jsx +0 -0
  132. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-unused-media.jsx +0 -0
  133. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-used-media-report.jsx +0 -0
  134. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-value-at-time.jsx +0 -0
  135. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-version-info.jsx +0 -0
  136. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-work-area.jsx +0 -0
  137. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-workspaces.jsx +0 -0
  138. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/get-xmp-metadata.jsx +0 -0
  139. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-ae-comps.jsx +0 -0
  140. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-fcp-xml.jsx +0 -0
  141. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-folder.jsx +0 -0
  142. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-image-sequence.jsx +0 -0
  143. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-media.jsx +0 -0
  144. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-mogrt-from-library.jsx +0 -0
  145. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-mogrt.jsx +0 -0
  146. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/import-sequences-from-project.jsx +0 -0
  147. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/insert-from-source.jsx +0 -0
  148. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/inspect-dom-object.jsx +0 -0
  149. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/invert-selection.jsx +0 -0
  150. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/is-work-area-enabled.jsx +0 -0
  151. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/lift-selection.jsx +0 -0
  152. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/link-selection.jsx +0 -0
  153. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-audio-effects.jsx +0 -0
  154. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-available-effects.jsx +0 -0
  155. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-markers.jsx +0 -0
  156. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/list-project-items.jsx +0 -0
  157. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/lock-track.jsx +0 -0
  158. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/manage-proxies.jsx +0 -0
  159. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/match-frame.jsx +0 -0
  160. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-clip-to-track.jsx +0 -0
  161. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-clip.jsx +0 -0
  162. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-items-to-bin.jsx +0 -0
  163. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-playhead-to-edit.jsx +0 -0
  164. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/move-playhead.jsx +0 -0
  165. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/nest-clips.jsx +0 -0
  166. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/open-in-source.jsx +0 -0
  167. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/open-project.jsx +0 -0
  168. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/overwrite-from-source.jsx +0 -0
  169. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/play-source-monitor.jsx +0 -0
  170. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/play-timeline.jsx +0 -0
  171. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/razor-all-tracks.jsx +0 -0
  172. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/redo.jsx +0 -0
  173. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/refresh-media.jsx +0 -0
  174. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/relink-media.jsx +0 -0
  175. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-all-effects.jsx +0 -0
  176. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-effect-by-name.jsx +0 -0
  177. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-effect.jsx +0 -0
  178. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-from-timeline.jsx +0 -0
  179. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-keyframe-range.jsx +0 -0
  180. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-keyframe.jsx +0 -0
  181. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-selected-clips.jsx +0 -0
  182. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-track-intervals.jsx +0 -0
  183. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/remove-transition.jsx +0 -0
  184. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-bin.jsx +0 -0
  185. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-clip.jsx +0 -0
  186. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-project-item.jsx +0 -0
  187. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/rename-track.jsx +0 -0
  188. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/replace-clip-media.jsx +0 -0
  189. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/replace-clip.jsx +0 -0
  190. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/reverse-clip.jsx +0 -0
  191. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/ripple-delete-clip.jsx +0 -0
  192. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/roll-edit.jsx +0 -0
  193. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/save-project-as.jsx +0 -0
  194. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/save-project.jsx +0 -0
  195. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/scene-edit-detection.jsx +0 -0
  196. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/search-project-items.jsx +0 -0
  197. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-all-clips.jsx +0 -0
  198. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-by-color.jsx +0 -0
  199. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-by-name.jsx +0 -0
  200. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-clips-in-range.jsx +0 -0
  201. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-disabled-clips.jsx +0 -0
  202. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/select-project-item.jsx +0 -0
  203. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-active-project.jsx +0 -0
  204. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-active-sequence.jsx +0 -0
  205. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-all-tracks-targeted.jsx +0 -0
  206. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-anti-alias-quality.jsx +0 -0
  207. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-blend-mode.jsx +0 -0
  208. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-anchor-point.jsx +0 -0
  209. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-enabled.jsx +0 -0
  210. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-opacity.jsx +0 -0
  211. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-pan.jsx +0 -0
  212. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-position.jsx +0 -0
  213. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-properties.jsx +0 -0
  214. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-rotation.jsx +0 -0
  215. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-scale.jsx +0 -0
  216. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-selection.jsx +0 -0
  217. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-speed.jsx +0 -0
  218. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-clip-volume.jsx +0 -0
  219. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-color-label.jsx +0 -0
  220. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-color-value.jsx +0 -0
  221. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-effect-property.jsx +0 -0
  222. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-footage-interpretation.jsx +0 -0
  223. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-frame-blend.jsx +0 -0
  224. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-graphics-white-luminance.jsx +0 -0
  225. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-in-out.jsx +0 -0
  226. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-metadata.jsx +0 -0
  227. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-offline.jsx +0 -0
  228. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-item-start-time.jsx +0 -0
  229. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-keyframe-interpolation.jsx +0 -0
  230. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-override-frame-rate.jsx +0 -0
  231. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-override-pixel-aspect-ratio.jsx +0 -0
  232. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-poster-frame.jsx +0 -0
  233. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-project-panel-metadata.jsx +0 -0
  234. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-scale-to-frame-size.jsx +0 -0
  235. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-scale-width-height.jsx +0 -0
  236. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-sequence-in-out.jsx +0 -0
  237. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-sequence-settings.jsx +0 -0
  238. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-source-in-out.jsx +0 -0
  239. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-target-track.jsx +0 -0
  240. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-time-interpolation.jsx +0 -0
  241. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-track-mute.jsx +0 -0
  242. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-track-visibility.jsx +0 -0
  243. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-transcode-on-ingest.jsx +0 -0
  244. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-uniform-scale.jsx +0 -0
  245. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-work-area.jsx +0 -0
  246. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-workspace.jsx +0 -0
  247. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/set-xmp-metadata.jsx +0 -0
  248. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/slide-edit.jsx +0 -0
  249. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/slip-edit.jsx +0 -0
  250. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/split-clip.jsx +0 -0
  251. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/stabilize-clip.jsx +0 -0
  252. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/stop-playback.jsx +0 -0
  253. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/trim-clip.jsx +0 -0
  254. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/undo.jsx +0 -0
  255. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/unlink-selection.jsx +0 -0
  256. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/unnest-sequence.jsx +0 -0
  257. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/commands/update-marker.jsx +0 -0
  258. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/host/presets/default-4k-25fps.sqpreset +0 -0
  259. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/index.html +0 -0
  260. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel/js/cs-interface.js +0 -0
  261. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/panel_install.py +0 -0
  262. {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
  263. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli/templates/empty-project/Untitled.prproj +0 -0
  264. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/dependency_links.txt +0 -0
  265. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/entry_points.txt +0 -0
  266. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/requires.txt +0 -0
  267. {premiere_cli-0.4.2 → premiere_cli-0.4.3}/src/premiere_cli.egg-info/top_level.txt +0 -0
  268. {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.2
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.2"
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"}
@@ -8,4 +8,4 @@ server (port 47823).
8
8
  # Kept in lockstep with PANEL_VERSION in panel/js/main.js and the version in
9
9
  # pyproject.toml — `premiere-cli doctor` compares the installed panel's
10
10
  # version against this one.
11
- __version__ = "0.4.2"
11
+ __version__ = "0.4.3"
@@ -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 (video only)")
1386
- add_transition_parser.add_argument("--track-index", type=int, required=True, help="0-based index of the video track")
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 transition)")
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 (video only, default: video)")
1399
- batch_add_transitions_parser.add_argument("--track-index", type=int, help="0-based index of the video track (default: 0)")
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 transition)")
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
+ }