vsview 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vsview/__init__.py +3 -0
- vsview/api/__init__.py +87 -0
- vsview/api/_helpers.py +53 -0
- vsview/api/info.py +6 -0
- vsview/api/output.py +338 -0
- vsview/app/__init__.py +0 -0
- vsview/app/error.py +102 -0
- vsview/app/main.py +756 -0
- vsview/app/outputs/__init__.py +7 -0
- vsview/app/outputs/audio.py +352 -0
- vsview/app/outputs/buffer.py +321 -0
- vsview/app/outputs/manager.py +154 -0
- vsview/app/outputs/packing.py +145 -0
- vsview/app/outputs/video.py +166 -0
- vsview/app/plugins/__init__.py +27 -0
- vsview/app/plugins/_interface.py +517 -0
- vsview/app/plugins/api.py +908 -0
- vsview/app/plugins/manager.py +259 -0
- vsview/app/plugins/specs.py +76 -0
- vsview/app/settings/__init__.py +8 -0
- vsview/app/settings/dialog.py +472 -0
- vsview/app/settings/enums.py +31 -0
- vsview/app/settings/manager.py +235 -0
- vsview/app/settings/models.py +1473 -0
- vsview/app/settings/secrets.py +194 -0
- vsview/app/settings/shortcuts.py +237 -0
- vsview/app/tools/__init__.py +0 -0
- vsview/app/tools/colorpicker/__init__.py +10 -0
- vsview/app/tools/colorpicker/plugin.py +504 -0
- vsview/app/tools/colorpicker/utils.py +81 -0
- vsview/app/tools/cropping/__init__.py +10 -0
- vsview/app/tools/cropping/plugin.py +270 -0
- vsview/app/tools/cropping/settings.py +61 -0
- vsview/app/tools/cropping/utils.py +114 -0
- vsview/app/tools/frameprops/__init__.py +11 -0
- vsview/app/tools/frameprops/api.py +5 -0
- vsview/app/tools/frameprops/builtins/field.py +26 -0
- vsview/app/tools/frameprops/builtins/metrics.py +35 -0
- vsview/app/tools/frameprops/builtins/video.py +77 -0
- vsview/app/tools/frameprops/categories.py +83 -0
- vsview/app/tools/frameprops/formatters.py +105 -0
- vsview/app/tools/frameprops/plugin.py +711 -0
- vsview/app/tools/frameprops/specs.py +22 -0
- vsview/app/tools/scening/__init__.py +10 -0
- vsview/app/tools/scening/api.py +137 -0
- vsview/app/tools/scening/models.py +229 -0
- vsview/app/tools/scening/parsers.py +328 -0
- vsview/app/tools/scening/plugin.py +762 -0
- vsview/app/tools/scening/serializer.py +53 -0
- vsview/app/tools/scening/specs.py +22 -0
- vsview/app/tools/scening/ui.py +706 -0
- vsview/app/tools/scening/utils.py +42 -0
- vsview/app/utils.py +183 -0
- vsview/app/views/__init__.py +6 -0
- vsview/app/views/components.py +392 -0
- vsview/app/views/plugins.py +113 -0
- vsview/app/views/status.py +319 -0
- vsview/app/views/tab.py +220 -0
- vsview/app/views/timeline.py +1771 -0
- vsview/app/views/video.py +1111 -0
- vsview/app/workspace/__init__.py +14 -0
- vsview/app/workspace/base.py +74 -0
- vsview/app/workspace/file.py +366 -0
- vsview/app/workspace/loader.py +826 -0
- vsview/app/workspace/playback.py +715 -0
- vsview/app/workspace/quick_script.py +501 -0
- vsview/app/workspace/tab_manager.py +368 -0
- vsview/assets/__init__.py +14 -0
- vsview/assets/fonts/Cascadia_Mono/CascadiaMono-Italic-VariableFont_wght.ttf +0 -0
- vsview/assets/fonts/Cascadia_Mono/CascadiaMono-VariableFont_wght.ttf +0 -0
- vsview/assets/fonts/Cascadia_Mono/LICENSE.txt +94 -0
- vsview/assets/icon.png +0 -0
- vsview/assets/icons/lucide/LICENSE +39 -0
- vsview/assets/icons/lucide/arrow-left.svg +14 -0
- vsview/assets/icons/lucide/arrow-right.svg +14 -0
- vsview/assets/icons/lucide/check.svg +13 -0
- vsview/assets/icons/lucide/circle-x.svg +15 -0
- vsview/assets/icons/lucide/clipboard.svg +14 -0
- vsview/assets/icons/lucide/fast-forward.svg +14 -0
- vsview/assets/icons/lucide/file-code.svg +16 -0
- vsview/assets/icons/lucide/file-down.svg +16 -0
- vsview/assets/icons/lucide/file-text.svg +17 -0
- vsview/assets/icons/lucide/file-up.svg +16 -0
- vsview/assets/icons/lucide/file-video-camera.svg +16 -0
- vsview/assets/icons/lucide/link-2.svg +15 -0
- vsview/assets/icons/lucide/link.svg +14 -0
- vsview/assets/icons/lucide/loader-circle.svg +13 -0
- vsview/assets/icons/lucide/minus.svg +13 -0
- vsview/assets/icons/lucide/move.svg +18 -0
- vsview/assets/icons/lucide/panel-right-open.svg +15 -0
- vsview/assets/icons/lucide/pause.svg +14 -0
- vsview/assets/icons/lucide/pipette.svg +15 -0
- vsview/assets/icons/lucide/play.svg +13 -0
- vsview/assets/icons/lucide/plus.svg +14 -0
- vsview/assets/icons/lucide/rewind.svg +14 -0
- vsview/assets/icons/lucide/save.svg +15 -0
- vsview/assets/icons/lucide/scan.svg +16 -0
- vsview/assets/icons/lucide/search-code.svg +16 -0
- vsview/assets/icons/lucide/skip-back.svg +14 -0
- vsview/assets/icons/lucide/skip-forward.svg +14 -0
- vsview/assets/icons/lucide/square-arrow-right-enter.svg +15 -0
- vsview/assets/icons/lucide/square-chevron-left.svg +14 -0
- vsview/assets/icons/lucide/square-chevron-right.svg +14 -0
- vsview/assets/icons/lucide/square-plus.svg +15 -0
- vsview/assets/icons/lucide/undo-2.svg +14 -0
- vsview/assets/icons/lucide/unlink-2.svg +13 -0
- vsview/assets/icons/lucide/unlink.svg +18 -0
- vsview/assets/icons/lucide/volume-1.svg +14 -0
- vsview/assets/icons/lucide/volume-2.svg +15 -0
- vsview/assets/icons/lucide/volume-off.svg +17 -0
- vsview/assets/icons/lucide/volume-x.svg +15 -0
- vsview/assets/icons/lucide/volume.svg +13 -0
- vsview/assets/icons/material/LICENSE +20 -0
- vsview/assets/icons/material/arrow-expand-all.svg +1 -0
- vsview/assets/icons/material/arrow-left.svg +1 -0
- vsview/assets/icons/material/arrow-right.svg +1 -0
- vsview/assets/icons/material/arrow-u-left-top.svg +1 -0
- vsview/assets/icons/material/border-radius.svg +1 -0
- vsview/assets/icons/material/check-outline.svg +1 -0
- vsview/assets/icons/material/check.svg +1 -0
- vsview/assets/icons/material/clipboard-outline.svg +1 -0
- vsview/assets/icons/material/clipboard.svg +1 -0
- vsview/assets/icons/material/close-circle-outline.svg +1 -0
- vsview/assets/icons/material/close-circle.svg +1 -0
- vsview/assets/icons/material/content-save-outline.svg +1 -0
- vsview/assets/icons/material/content-save.svg +1 -0
- vsview/assets/icons/material/eyedropper.svg +1 -0
- vsview/assets/icons/material/fast-forward-outline.svg +1 -0
- vsview/assets/icons/material/fast-forward.svg +1 -0
- vsview/assets/icons/material/file-code-outline.svg +1 -0
- vsview/assets/icons/material/file-code.svg +1 -0
- vsview/assets/icons/material/file-document-outline.svg +1 -0
- vsview/assets/icons/material/file-document.svg +1 -0
- vsview/assets/icons/material/file-export-outline.svg +1 -0
- vsview/assets/icons/material/file-export.svg +1 -0
- vsview/assets/icons/material/file-import-outline.svg +1 -0
- vsview/assets/icons/material/file-import.svg +1 -0
- vsview/assets/icons/material/file-video-outline.svg +1 -0
- vsview/assets/icons/material/file-video.svg +1 -0
- vsview/assets/icons/material/link-variant-minus.svg +1 -0
- vsview/assets/icons/material/link-variant-off.svg +1 -0
- vsview/assets/icons/material/link-variant-plus.svg +1 -0
- vsview/assets/icons/material/link-variant.svg +1 -0
- vsview/assets/icons/material/loading.svg +1 -0
- vsview/assets/icons/material/magnify.svg +1 -0
- vsview/assets/icons/material/minus.svg +1 -0
- vsview/assets/icons/material/page-layout-sidebar-right.svg +1 -0
- vsview/assets/icons/material/pause.svg +1 -0
- vsview/assets/icons/material/play-outline.svg +1 -0
- vsview/assets/icons/material/play.svg +1 -0
- vsview/assets/icons/material/plus-box-multiple-outline.svg +1 -0
- vsview/assets/icons/material/plus-box-multiple.svg +1 -0
- vsview/assets/icons/material/plus-box-outline.svg +1 -0
- vsview/assets/icons/material/plus-box.svg +1 -0
- vsview/assets/icons/material/plus-outline.svg +1 -0
- vsview/assets/icons/material/plus.svg +1 -0
- vsview/assets/icons/material/rewind-outline.svg +1 -0
- vsview/assets/icons/material/rewind.svg +1 -0
- vsview/assets/icons/material/skip-next-outline.svg +1 -0
- vsview/assets/icons/material/skip-next.svg +1 -0
- vsview/assets/icons/material/skip-previous-outline.svg +1 -0
- vsview/assets/icons/material/skip-previous.svg +1 -0
- vsview/assets/icons/material/step-backward.svg +1 -0
- vsview/assets/icons/material/step-forward.svg +1 -0
- vsview/assets/icons/material/volume-high.svg +1 -0
- vsview/assets/icons/material/volume-low.svg +1 -0
- vsview/assets/icons/material/volume-medium.svg +1 -0
- vsview/assets/icons/material/volume-mute.svg +1 -0
- vsview/assets/icons/material/volume-off.svg +1 -0
- vsview/assets/icons/phosphor/LICENSE +21 -0
- vsview/assets/icons/phosphor/arrow-left-bold.svg +1 -0
- vsview/assets/icons/phosphor/arrow-left-duotone.svg +1 -0
- vsview/assets/icons/phosphor/arrow-left-fill.svg +1 -0
- vsview/assets/icons/phosphor/arrow-left-light.svg +1 -0
- vsview/assets/icons/phosphor/arrow-left-thin.svg +1 -0
- vsview/assets/icons/phosphor/arrow-left.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right-bold.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right-duotone.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right-fill.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right-light.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right-thin.svg +1 -0
- vsview/assets/icons/phosphor/arrow-right.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left-bold.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left-duotone.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left-fill.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left-light.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left-thin.svg +1 -0
- vsview/assets/icons/phosphor/arrow-u-up-left.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal-bold.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal-duotone.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal-fill.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal-light.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal-thin.svg +1 -0
- vsview/assets/icons/phosphor/arrows-out-cardinal.svg +1 -0
- vsview/assets/icons/phosphor/check-bold.svg +1 -0
- vsview/assets/icons/phosphor/check-duotone.svg +1 -0
- vsview/assets/icons/phosphor/check-fill.svg +1 -0
- vsview/assets/icons/phosphor/check-light.svg +1 -0
- vsview/assets/icons/phosphor/check-thin.svg +1 -0
- vsview/assets/icons/phosphor/check.svg +1 -0
- vsview/assets/icons/phosphor/clipboard-bold.svg +1 -0
- vsview/assets/icons/phosphor/clipboard-duotone.svg +1 -0
- vsview/assets/icons/phosphor/clipboard-fill.svg +1 -0
- vsview/assets/icons/phosphor/clipboard-light.svg +1 -0
- vsview/assets/icons/phosphor/clipboard-thin.svg +1 -0
- vsview/assets/icons/phosphor/clipboard.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper-bold.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper-duotone.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper-fill.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper-light.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper-thin.svg +1 -0
- vsview/assets/icons/phosphor/eyedropper.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward-bold.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward-duotone.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward-fill.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward-light.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward-thin.svg +1 -0
- vsview/assets/icons/phosphor/fast-forward.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down-bold.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down-duotone.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down-fill.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down-light.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down-thin.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-down.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up-bold.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up-duotone.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up-fill.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up-light.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up-thin.svg +1 -0
- vsview/assets/icons/phosphor/file-arrow-up.svg +1 -0
- vsview/assets/icons/phosphor/file-code-bold.svg +1 -0
- vsview/assets/icons/phosphor/file-code-duotone.svg +1 -0
- vsview/assets/icons/phosphor/file-code-fill.svg +1 -0
- vsview/assets/icons/phosphor/file-code-light.svg +1 -0
- vsview/assets/icons/phosphor/file-code-thin.svg +1 -0
- vsview/assets/icons/phosphor/file-code.svg +1 -0
- vsview/assets/icons/phosphor/file-text-bold.svg +1 -0
- vsview/assets/icons/phosphor/file-text-duotone.svg +1 -0
- vsview/assets/icons/phosphor/file-text-fill.svg +1 -0
- vsview/assets/icons/phosphor/file-text-light.svg +1 -0
- vsview/assets/icons/phosphor/file-text-thin.svg +1 -0
- vsview/assets/icons/phosphor/file-text.svg +1 -0
- vsview/assets/icons/phosphor/file-video-bold.svg +1 -0
- vsview/assets/icons/phosphor/file-video-duotone.svg +1 -0
- vsview/assets/icons/phosphor/file-video-fill.svg +1 -0
- vsview/assets/icons/phosphor/file-video-light.svg +1 -0
- vsview/assets/icons/phosphor/file-video-thin.svg +1 -0
- vsview/assets/icons/phosphor/file-video.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk-bold.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk-duotone.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk-fill.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk-light.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk-thin.svg +1 -0
- vsview/assets/icons/phosphor/floppy-disk.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners-bold.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners-duotone.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners-fill.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners-light.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners-thin.svg +1 -0
- vsview/assets/icons/phosphor/frame-corners.svg +1 -0
- vsview/assets/icons/phosphor/link-bold.svg +1 -0
- vsview/assets/icons/phosphor/link-break-bold.svg +1 -0
- vsview/assets/icons/phosphor/link-break-duotone.svg +1 -0
- vsview/assets/icons/phosphor/link-break-fill.svg +1 -0
- vsview/assets/icons/phosphor/link-break-light.svg +1 -0
- vsview/assets/icons/phosphor/link-break-thin.svg +1 -0
- vsview/assets/icons/phosphor/link-break.svg +1 -0
- vsview/assets/icons/phosphor/link-duotone.svg +1 -0
- vsview/assets/icons/phosphor/link-fill.svg +1 -0
- vsview/assets/icons/phosphor/link-light.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-bold.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break-bold.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break-duotone.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break-fill.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break-light.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break-thin.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-break.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-duotone.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-fill.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-light.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal-thin.svg +1 -0
- vsview/assets/icons/phosphor/link-simple-horizontal.svg +1 -0
- vsview/assets/icons/phosphor/link-thin.svg +1 -0
- vsview/assets/icons/phosphor/link.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass-bold.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass-duotone.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass-fill.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass-light.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass-thin.svg +1 -0
- vsview/assets/icons/phosphor/magnifying-glass.svg +1 -0
- vsview/assets/icons/phosphor/minus-bold.svg +1 -0
- vsview/assets/icons/phosphor/minus-duotone.svg +1 -0
- vsview/assets/icons/phosphor/minus-fill.svg +1 -0
- vsview/assets/icons/phosphor/minus-light.svg +1 -0
- vsview/assets/icons/phosphor/minus-thin.svg +1 -0
- vsview/assets/icons/phosphor/minus.svg +1 -0
- vsview/assets/icons/phosphor/pause-bold.svg +1 -0
- vsview/assets/icons/phosphor/pause-duotone.svg +1 -0
- vsview/assets/icons/phosphor/pause-fill.svg +1 -0
- vsview/assets/icons/phosphor/pause-light.svg +1 -0
- vsview/assets/icons/phosphor/pause-thin.svg +1 -0
- vsview/assets/icons/phosphor/pause.svg +1 -0
- vsview/assets/icons/phosphor/play-bold.svg +1 -0
- vsview/assets/icons/phosphor/play-duotone.svg +1 -0
- vsview/assets/icons/phosphor/play-fill.svg +1 -0
- vsview/assets/icons/phosphor/play-light.svg +1 -0
- vsview/assets/icons/phosphor/play-thin.svg +1 -0
- vsview/assets/icons/phosphor/play.svg +1 -0
- vsview/assets/icons/phosphor/plus-bold.svg +1 -0
- vsview/assets/icons/phosphor/plus-duotone.svg +1 -0
- vsview/assets/icons/phosphor/plus-fill.svg +1 -0
- vsview/assets/icons/phosphor/plus-light.svg +1 -0
- vsview/assets/icons/phosphor/plus-thin.svg +1 -0
- vsview/assets/icons/phosphor/plus.svg +1 -0
- vsview/assets/icons/phosphor/rewind-bold.svg +1 -0
- vsview/assets/icons/phosphor/rewind-duotone.svg +1 -0
- vsview/assets/icons/phosphor/rewind-fill.svg +1 -0
- vsview/assets/icons/phosphor/rewind-light.svg +1 -0
- vsview/assets/icons/phosphor/rewind-thin.svg +1 -0
- vsview/assets/icons/phosphor/rewind.svg +1 -0
- vsview/assets/icons/phosphor/selection-background-bold.svg +1 -0
- vsview/assets/icons/phosphor/selection-background-duotone.svg +1 -0
- vsview/assets/icons/phosphor/selection-background-fill.svg +1 -0
- vsview/assets/icons/phosphor/selection-background-light.svg +1 -0
- vsview/assets/icons/phosphor/selection-background-thin.svg +1 -0
- vsview/assets/icons/phosphor/selection-background.svg +1 -0
- vsview/assets/icons/phosphor/selection-bold.svg +1 -0
- vsview/assets/icons/phosphor/selection-duotone.svg +1 -0
- vsview/assets/icons/phosphor/selection-fill.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground-bold.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground-duotone.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground-fill.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground-light.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground-thin.svg +1 -0
- vsview/assets/icons/phosphor/selection-foreground.svg +1 -0
- vsview/assets/icons/phosphor/selection-light.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus-bold.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus-duotone.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus-fill.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus-light.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus-thin.svg +1 -0
- vsview/assets/icons/phosphor/selection-plus.svg +1 -0
- vsview/assets/icons/phosphor/selection-thin.svg +1 -0
- vsview/assets/icons/phosphor/selection.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple-bold.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple-duotone.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple-fill.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple-light.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple-thin.svg +1 -0
- vsview/assets/icons/phosphor/sidebar-simple.svg +1 -0
- vsview/assets/icons/phosphor/skip-back-bold.svg +1 -0
- vsview/assets/icons/phosphor/skip-back-duotone.svg +1 -0
- vsview/assets/icons/phosphor/skip-back-fill.svg +1 -0
- vsview/assets/icons/phosphor/skip-back-light.svg +1 -0
- vsview/assets/icons/phosphor/skip-back-thin.svg +1 -0
- vsview/assets/icons/phosphor/skip-back.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward-bold.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward-duotone.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward-fill.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward-light.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward-thin.svg +1 -0
- vsview/assets/icons/phosphor/skip-forward.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high-bold.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high-duotone.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high-fill.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high-light.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high-thin.svg +1 -0
- vsview/assets/icons/phosphor/speaker-high.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low-bold.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low-duotone.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low-fill.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low-light.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low-thin.svg +1 -0
- vsview/assets/icons/phosphor/speaker-low.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none-bold.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none-duotone.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none-fill.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none-light.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none-thin.svg +1 -0
- vsview/assets/icons/phosphor/speaker-none.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash-bold.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash-duotone.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash-fill.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash-light.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash-thin.svg +1 -0
- vsview/assets/icons/phosphor/speaker-slash.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x-bold.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x-duotone.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x-fill.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x-light.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x-thin.svg +1 -0
- vsview/assets/icons/phosphor/speaker-x.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap-bold.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap-duotone.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap-fill.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap-light.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap-thin.svg +1 -0
- vsview/assets/icons/phosphor/spinner-gap.svg +1 -0
- vsview/assets/icons/phosphor/x-circle-bold.svg +1 -0
- vsview/assets/icons/phosphor/x-circle-duotone.svg +1 -0
- vsview/assets/icons/phosphor/x-circle-fill.svg +1 -0
- vsview/assets/icons/phosphor/x-circle-light.svg +1 -0
- vsview/assets/icons/phosphor/x-circle-thin.svg +1 -0
- vsview/assets/icons/phosphor/x-circle.svg +1 -0
- vsview/assets/loading.png +0 -0
- vsview/assets/providers.py +249 -0
- vsview/assets/utils.py +466 -0
- vsview/cli.py +240 -0
- vsview/env.py +7 -0
- vsview/logging.py +103 -0
- vsview/py.typed +0 -0
- vsview/vsenv/__init__.py +15 -0
- vsview/vsenv/gc.py +14 -0
- vsview/vsenv/loop.py +253 -0
- vsview/vsenv/policy.py +138 -0
- vsview-0.1.0.dist-info/METADATA +79 -0
- vsview-0.1.0.dist-info/RECORD +425 -0
- vsview-0.1.0.dist-info/WHEEL +4 -0
- vsview-0.1.0.dist-info/entry_points.txt +2 -0
- vsview-0.1.0.dist-info/licenses/LICENSE +291 -0
- vsview-0.1.0.dist-info/licenses/src/vsview/assets/fonts/Cascadia_Mono/LICENSE.txt +94 -0
- vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/lucide/LICENSE +39 -0
- vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/material/LICENSE +20 -0
- vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/phosphor/LICENSE +21 -0
- vsview-0.1.0.dist-info/sboms/sboms.json +357 -0
vsview/__init__.py
ADDED
vsview/api/__init__.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""API for vsview"""
|
|
2
|
+
|
|
3
|
+
from ..app.plugins import (
|
|
4
|
+
AudioOutputProxy,
|
|
5
|
+
GraphicsViewProxy,
|
|
6
|
+
LocalSettingsModel,
|
|
7
|
+
NodeProcessor,
|
|
8
|
+
PluginAPI,
|
|
9
|
+
PluginGraphicsView,
|
|
10
|
+
PluginSecrets,
|
|
11
|
+
PluginSettings,
|
|
12
|
+
VideoOutputProxy,
|
|
13
|
+
WidgetPluginBase,
|
|
14
|
+
hookimpl,
|
|
15
|
+
)
|
|
16
|
+
from ..app.settings.models import (
|
|
17
|
+
ActionDefinition,
|
|
18
|
+
Checkbox,
|
|
19
|
+
ColorPicker,
|
|
20
|
+
ColorPickerInput,
|
|
21
|
+
DoubleSpin,
|
|
22
|
+
Dropdown,
|
|
23
|
+
LineEdit,
|
|
24
|
+
ListEdit,
|
|
25
|
+
ListEditWidget,
|
|
26
|
+
Login,
|
|
27
|
+
LoginCredentialsInput,
|
|
28
|
+
PlainTextEdit,
|
|
29
|
+
Spin,
|
|
30
|
+
WidgetMetadata,
|
|
31
|
+
WidgetTimeEdit,
|
|
32
|
+
)
|
|
33
|
+
from ..app.views import OutputInfo
|
|
34
|
+
from ..app.views.components import AbstractTableModel, Accordion, AnimatedToggle, NonClosingMenu, SegmentedControl
|
|
35
|
+
from ..app.views.timeline import Frame, FrameEdit, Time, TimeEdit
|
|
36
|
+
from ..app.views.video import BaseGraphicsView
|
|
37
|
+
from ..assets import IconName, IconReloadMixin
|
|
38
|
+
from ..vsenv import run_in_background, run_in_loop
|
|
39
|
+
from .info import is_preview
|
|
40
|
+
from .output import catch_output, set_output
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"AbstractTableModel",
|
|
44
|
+
"Accordion",
|
|
45
|
+
"ActionDefinition",
|
|
46
|
+
"AnimatedToggle",
|
|
47
|
+
"AudioOutputProxy",
|
|
48
|
+
"BaseGraphicsView",
|
|
49
|
+
"Checkbox",
|
|
50
|
+
"ColorPicker",
|
|
51
|
+
"ColorPickerInput",
|
|
52
|
+
"DoubleSpin",
|
|
53
|
+
"Dropdown",
|
|
54
|
+
"Frame",
|
|
55
|
+
"FrameEdit",
|
|
56
|
+
"GraphicsViewProxy",
|
|
57
|
+
"IconName",
|
|
58
|
+
"IconReloadMixin",
|
|
59
|
+
"LineEdit",
|
|
60
|
+
"ListEdit",
|
|
61
|
+
"ListEditWidget",
|
|
62
|
+
"LocalSettingsModel",
|
|
63
|
+
"Login",
|
|
64
|
+
"LoginCredentialsInput",
|
|
65
|
+
"NodeProcessor",
|
|
66
|
+
"NonClosingMenu",
|
|
67
|
+
"OutputInfo",
|
|
68
|
+
"PlainTextEdit",
|
|
69
|
+
"PluginAPI",
|
|
70
|
+
"PluginGraphicsView",
|
|
71
|
+
"PluginSecrets",
|
|
72
|
+
"PluginSettings",
|
|
73
|
+
"SegmentedControl",
|
|
74
|
+
"Spin",
|
|
75
|
+
"Time",
|
|
76
|
+
"TimeEdit",
|
|
77
|
+
"VideoOutputProxy",
|
|
78
|
+
"WidgetMetadata",
|
|
79
|
+
"WidgetPluginBase",
|
|
80
|
+
"WidgetTimeEdit",
|
|
81
|
+
"catch_output",
|
|
82
|
+
"hookimpl",
|
|
83
|
+
"is_preview",
|
|
84
|
+
"run_in_background",
|
|
85
|
+
"run_in_loop",
|
|
86
|
+
"set_output",
|
|
87
|
+
]
|
vsview/api/_helpers.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from collections import UserDict, defaultdict
|
|
2
|
+
from collections.abc import Callable, Sequence
|
|
3
|
+
from os import PathLike
|
|
4
|
+
from typing import Any, Literal, NamedTuple
|
|
5
|
+
|
|
6
|
+
from jetpytools import copy_signature
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class VideoMetadata(NamedTuple):
|
|
10
|
+
name: str
|
|
11
|
+
framedurs: Sequence[float] | None
|
|
12
|
+
alpha_prop: Literal[True] | None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AudioMetadata(NamedTuple):
|
|
16
|
+
name: str
|
|
17
|
+
downmix: bool | None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DefaultUserDict[K, V](UserDict[K, V]):
|
|
21
|
+
@copy_signature(defaultdict[K, V].__init__)
|
|
22
|
+
def __init__(self, default_factory: Callable[[], V] | None = None, /, *args: Any, **kwargs: Any) -> None:
|
|
23
|
+
super().__init__(*args, **kwargs)
|
|
24
|
+
self.default_factory = default_factory
|
|
25
|
+
|
|
26
|
+
def __missing__(self, key: K) -> V:
|
|
27
|
+
if self.default_factory is None:
|
|
28
|
+
raise KeyError(key)
|
|
29
|
+
|
|
30
|
+
new_value = self.default_factory()
|
|
31
|
+
|
|
32
|
+
self.data[key] = new_value
|
|
33
|
+
|
|
34
|
+
return new_value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class OutputMetadata(DefaultUserDict[str, dict[int, Any]]):
|
|
38
|
+
def _hash_key(self, key: str | PathLike[str]) -> str:
|
|
39
|
+
from ..app.utils import path_to_hash
|
|
40
|
+
|
|
41
|
+
return path_to_hash(key)
|
|
42
|
+
|
|
43
|
+
def __getitem__(self, key: str | PathLike[str]) -> dict[int, Any]:
|
|
44
|
+
return super().__getitem__(self._hash_key(key))
|
|
45
|
+
|
|
46
|
+
def __setitem__(self, key: str | PathLike[str], value: dict[int, Any]) -> None:
|
|
47
|
+
super().__setitem__(self._hash_key(key), value)
|
|
48
|
+
|
|
49
|
+
def __contains__(self, key: object) -> bool:
|
|
50
|
+
return super().__contains__(self._hash_key(str(key)))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
output_metadata = OutputMetadata(dict)
|
vsview/api/info.py
ADDED
vsview/api/output.py
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Output registration API for vsview.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import sys
|
|
8
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
9
|
+
from copy import deepcopy
|
|
10
|
+
from functools import wraps
|
|
11
|
+
from logging import getLogger
|
|
12
|
+
from typing import Any, Literal, assert_never, overload
|
|
13
|
+
|
|
14
|
+
import vapoursynth as vs
|
|
15
|
+
from jetpytools import CustomValueError, flatten, to_arr
|
|
16
|
+
|
|
17
|
+
from ._helpers import AudioMetadata, VideoMetadata
|
|
18
|
+
from ._helpers import output_metadata as _output_metadata
|
|
19
|
+
|
|
20
|
+
_logger = getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
type VideoNodeIterable = Iterable[vs.VideoNode | VideoNodeIterable]
|
|
23
|
+
type AudioNodeIterable = Iterable[vs.AudioNode | AudioNodeIterable]
|
|
24
|
+
type OutputNode = vs.VideoNode | vs.AudioNode | VideoNodeIterable | AudioNodeIterable
|
|
25
|
+
|
|
26
|
+
# ScenesT = Keyframes | list[tuple[int, int]] | list[Keyframes | list[tuple[int, int]]] | None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# VideoNode signature
|
|
30
|
+
@overload
|
|
31
|
+
def set_output(
|
|
32
|
+
node: vs.VideoNode,
|
|
33
|
+
index: int = ...,
|
|
34
|
+
/,
|
|
35
|
+
*,
|
|
36
|
+
alpha: vs.VideoNode | Literal[True] | None = ...,
|
|
37
|
+
framedurs: Sequence[float] | None = None,
|
|
38
|
+
# scenes: ScenesT = None,
|
|
39
|
+
**kwargs: Any,
|
|
40
|
+
) -> None: ...
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@overload
|
|
44
|
+
def set_output(
|
|
45
|
+
node: vs.VideoNode,
|
|
46
|
+
name: str | bool | None = ...,
|
|
47
|
+
/,
|
|
48
|
+
*,
|
|
49
|
+
alpha: vs.VideoNode | Literal[True] | None = ...,
|
|
50
|
+
framedurs: Sequence[float] | None = None,
|
|
51
|
+
# scenes: ScenesT = None,
|
|
52
|
+
**kwargs: Any,
|
|
53
|
+
) -> None: ...
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@overload
|
|
57
|
+
def set_output(
|
|
58
|
+
node: vs.VideoNode,
|
|
59
|
+
index: int = ...,
|
|
60
|
+
name: str | bool | None = ...,
|
|
61
|
+
/,
|
|
62
|
+
alpha: vs.VideoNode | Literal[True] | None = ...,
|
|
63
|
+
*,
|
|
64
|
+
framedurs: Sequence[float] | None = None,
|
|
65
|
+
# scenes: ScenesT = None,
|
|
66
|
+
**kwargs: Any,
|
|
67
|
+
) -> None: ...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# AudioNode signature
|
|
71
|
+
@overload
|
|
72
|
+
def set_output(
|
|
73
|
+
node: vs.AudioNode,
|
|
74
|
+
index: int = ...,
|
|
75
|
+
/,
|
|
76
|
+
*,
|
|
77
|
+
downmix: bool | None = None,
|
|
78
|
+
**kwargs: Any,
|
|
79
|
+
) -> None: ...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@overload
|
|
83
|
+
def set_output(
|
|
84
|
+
node: vs.AudioNode,
|
|
85
|
+
name: str | bool | None = ...,
|
|
86
|
+
/,
|
|
87
|
+
*,
|
|
88
|
+
downmix: bool | None = None,
|
|
89
|
+
**kwargs: Any,
|
|
90
|
+
) -> None: ...
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@overload
|
|
94
|
+
def set_output(
|
|
95
|
+
node: vs.AudioNode,
|
|
96
|
+
index: int = ...,
|
|
97
|
+
name: str | bool | None = ...,
|
|
98
|
+
/,
|
|
99
|
+
*,
|
|
100
|
+
downmix: bool | None = None,
|
|
101
|
+
**kwargs: Any,
|
|
102
|
+
) -> None: ...
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@overload
|
|
106
|
+
def set_output(
|
|
107
|
+
node: VideoNodeIterable | AudioNodeIterable, index: int | Sequence[int] = ..., /, **kwargs: Any
|
|
108
|
+
) -> None: ...
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@overload
|
|
112
|
+
def set_output(
|
|
113
|
+
node: VideoNodeIterable | AudioNodeIterable, name: str | bool | None = ..., /, **kwargs: Any
|
|
114
|
+
) -> None: ...
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@overload
|
|
118
|
+
def set_output(
|
|
119
|
+
node: VideoNodeIterable | AudioNodeIterable,
|
|
120
|
+
index: int | Sequence[int] = ...,
|
|
121
|
+
name: str | bool | None = ...,
|
|
122
|
+
/,
|
|
123
|
+
**kwargs: Any,
|
|
124
|
+
) -> None: ...
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def set_output(
|
|
128
|
+
node: OutputNode,
|
|
129
|
+
index_or_name: int | Sequence[int] | str | bool | None = None,
|
|
130
|
+
name: str | bool | None = None,
|
|
131
|
+
/,
|
|
132
|
+
alpha: vs.VideoNode | Literal[True] | None = None,
|
|
133
|
+
*,
|
|
134
|
+
framedurs: Sequence[float] | None = None,
|
|
135
|
+
# scenes: ScenesT = None,
|
|
136
|
+
downmix: bool | None = None,
|
|
137
|
+
**kwargs: Any,
|
|
138
|
+
) -> None:
|
|
139
|
+
"""
|
|
140
|
+
Register one or more VapourSynth nodes as outputs for preview.
|
|
141
|
+
|
|
142
|
+
This function sets the output(s) and registers metadata for tab naming in vsview.
|
|
143
|
+
If no index is provided, outputs are assigned to the next available indices.
|
|
144
|
+
|
|
145
|
+
Examples:
|
|
146
|
+
```python
|
|
147
|
+
set_output(clip) # Auto-index, auto-name ("clip")
|
|
148
|
+
set_output(clip, 0) # Index 0, auto-name
|
|
149
|
+
set_output(clip, 0, "My Clip") # Index 0, explicit name
|
|
150
|
+
set_output(clip, "Source") # Auto-index, explicit name
|
|
151
|
+
set_output([clip1, clip2]) # Multiple outputs
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
node: A VideoNode, AudioNode, or iterable of nodes to output.
|
|
156
|
+
index_or_name: Either:
|
|
157
|
+
|
|
158
|
+
- An int or sequence of ints specifying output indices
|
|
159
|
+
- A str to use as the output name
|
|
160
|
+
- True/None to auto-detect the variable name
|
|
161
|
+
- False to disable name detection
|
|
162
|
+
|
|
163
|
+
name: Explicit name override. If provided when index_or_name is an int,
|
|
164
|
+
this sets the display name for the output.
|
|
165
|
+
alpha: Optional alpha channel VideoNode or if True, fetch the `_Alpha` prop (only for VideoNode outputs).
|
|
166
|
+
framedurs: Optional sequence of frame durations in seconds for VFR clips (only for VideoNode outputs).
|
|
167
|
+
downmix: if None (default), follows the global settings downmix of vsview if previewed
|
|
168
|
+
through vsview. Otherwise True or False forces the behavior.
|
|
169
|
+
**kwargs: Additional keyword arguments (reserved for future use).
|
|
170
|
+
"""
|
|
171
|
+
if isinstance(index_or_name, (str, bool)):
|
|
172
|
+
index = None
|
|
173
|
+
name = index_or_name
|
|
174
|
+
else:
|
|
175
|
+
index = index_or_name
|
|
176
|
+
|
|
177
|
+
outputs = vs.get_outputs()
|
|
178
|
+
nodes = list[vs.VideoNode | vs.AudioNode](flatten([node]))
|
|
179
|
+
|
|
180
|
+
indices = to_arr(index) if index is not None else [max(outputs, default=-1) + 1]
|
|
181
|
+
|
|
182
|
+
while len(indices) < len(nodes):
|
|
183
|
+
indices.append(indices[-1] + 1)
|
|
184
|
+
|
|
185
|
+
frame_depth = kwargs.pop("frame_depth", 1) + 1
|
|
186
|
+
script_module = sys.modules.get("__vsview__")
|
|
187
|
+
|
|
188
|
+
for i, n in zip(indices[: len(nodes)], nodes):
|
|
189
|
+
if i in outputs:
|
|
190
|
+
_logger.warning("Output index %d already in use; overwriting.", i)
|
|
191
|
+
|
|
192
|
+
match n:
|
|
193
|
+
case vs.VideoNode():
|
|
194
|
+
n.set_output(i, alpha if alpha is not True else None)
|
|
195
|
+
title = "Clip"
|
|
196
|
+
case vs.AudioNode():
|
|
197
|
+
n.set_output(i)
|
|
198
|
+
title = "Audio"
|
|
199
|
+
case _:
|
|
200
|
+
assert_never(n)
|
|
201
|
+
|
|
202
|
+
if not script_module:
|
|
203
|
+
continue
|
|
204
|
+
|
|
205
|
+
effective_name: str | None
|
|
206
|
+
|
|
207
|
+
match name:
|
|
208
|
+
case True | None:
|
|
209
|
+
effective_name = _resolve_var_name(n, frame_depth=frame_depth)
|
|
210
|
+
case False:
|
|
211
|
+
effective_name = None
|
|
212
|
+
case str():
|
|
213
|
+
effective_name = name
|
|
214
|
+
|
|
215
|
+
if file := getattr(script_module, "__file__", None):
|
|
216
|
+
if isinstance(n, vs.VideoNode):
|
|
217
|
+
if framedurs and len(framedurs) != n.num_frames:
|
|
218
|
+
raise CustomValueError(
|
|
219
|
+
"framedurs length must match number of frames", kwargs.get("func", set_output)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
_output_metadata[file][i] = VideoMetadata(
|
|
223
|
+
effective_name or f"{title} {i}",
|
|
224
|
+
deepcopy(framedurs),
|
|
225
|
+
alpha is True or None,
|
|
226
|
+
)
|
|
227
|
+
elif isinstance(n, vs.AudioNode):
|
|
228
|
+
_output_metadata[file][i] = AudioMetadata(effective_name or f"{title} {i}", downmix)
|
|
229
|
+
|
|
230
|
+
# if scenes:
|
|
231
|
+
# set_scening(scenes, n, effective_name or f"{title} {i}")
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@overload
|
|
235
|
+
def catch_output[**P, N: OutputNode](func: Callable[P, N], /) -> Callable[P, N]: ...
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
@overload
|
|
239
|
+
def catch_output[**P, N: OutputNode](
|
|
240
|
+
*,
|
|
241
|
+
index: int | Sequence[int] = ...,
|
|
242
|
+
name: str | bool | None = ...,
|
|
243
|
+
alpha: vs.VideoNode | Literal[True] | None = ...,
|
|
244
|
+
framedurs: Sequence[float] | None = ...,
|
|
245
|
+
downmix: bool | None = ...,
|
|
246
|
+
**kwargs: Any,
|
|
247
|
+
) -> Callable[[Callable[P, N]], Callable[P, N]]: ...
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def catch_output[**P, N: OutputNode](
|
|
251
|
+
func: Callable[P, N] | None = None,
|
|
252
|
+
/,
|
|
253
|
+
index: int | Sequence[int] | None = None,
|
|
254
|
+
name: str | bool | None = None,
|
|
255
|
+
alpha: vs.VideoNode | Literal[True] | None = None,
|
|
256
|
+
*,
|
|
257
|
+
framedurs: Sequence[float] | None = None,
|
|
258
|
+
downmix: bool | None = None,
|
|
259
|
+
**kwargs: Any,
|
|
260
|
+
) -> Callable[P, N] | Callable[[Callable[P, N]], Callable[P, N]]:
|
|
261
|
+
"""
|
|
262
|
+
Decorator variant of `set_output()`.
|
|
263
|
+
|
|
264
|
+
Calls the decorated function and registers its return value as an output.
|
|
265
|
+
|
|
266
|
+
Examples:
|
|
267
|
+
```python
|
|
268
|
+
@catch_output
|
|
269
|
+
def source() -> vs.VideNode:
|
|
270
|
+
return vs.core.bs.BestSource("video.mkv")
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@catch_output(name="Filtered", alpha=True)
|
|
274
|
+
def filtered() -> vs.VideNode:
|
|
275
|
+
src = vs.core.bs.BestSource("image.png")
|
|
276
|
+
return src.std.BoxBlur()
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
func: The function to decorate (populated automatically when used as a bare decorator).
|
|
281
|
+
index: An int or sequence of ints specifying output indices
|
|
282
|
+
name: Explicit name override. If not provided, the function name is used.
|
|
283
|
+
alpha: Optional alpha channel VideoNode or if True, fetch the `_Alpha` prop (only for VideoNode outputs).
|
|
284
|
+
framedurs: Optional sequence of frame durations in seconds for VFR clips (only for VideoNode outputs).
|
|
285
|
+
downmix: If None (default), follows the global settings downmix of vsview if previewed through vsview.
|
|
286
|
+
Otherwise True or False forces the behavior.
|
|
287
|
+
**kwargs: Additional keyword arguments forwarded to :func:`set_output`.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
The decorated function (its original return type is preserved).
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
def decorator(fn: Callable[P, N]) -> Callable[P, N]:
|
|
294
|
+
@wraps(fn)
|
|
295
|
+
def wrapper(*fn_args: P.args, **fn_kwargs: P.kwargs) -> N:
|
|
296
|
+
nonlocal name
|
|
297
|
+
|
|
298
|
+
result = fn(*fn_args, **fn_kwargs)
|
|
299
|
+
|
|
300
|
+
if name is True or name is None:
|
|
301
|
+
name = fn.__name__
|
|
302
|
+
|
|
303
|
+
set_output( # type: ignore[misc]
|
|
304
|
+
result, # type: ignore[arg-type]
|
|
305
|
+
index, # type: ignore[arg-type]
|
|
306
|
+
name,
|
|
307
|
+
alpha=alpha,
|
|
308
|
+
framedurs=framedurs,
|
|
309
|
+
downmix=downmix,
|
|
310
|
+
**kwargs,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
return result
|
|
314
|
+
|
|
315
|
+
return wrapper
|
|
316
|
+
|
|
317
|
+
if func is not None:
|
|
318
|
+
return decorator(func)
|
|
319
|
+
|
|
320
|
+
return decorator
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def _resolve_var_name(obj: Any, *, frame_depth: int = 1) -> str | None:
|
|
324
|
+
try:
|
|
325
|
+
frame = sys._getframe(frame_depth)
|
|
326
|
+
except ValueError:
|
|
327
|
+
return None
|
|
328
|
+
|
|
329
|
+
try:
|
|
330
|
+
obj_id = id(obj)
|
|
331
|
+
|
|
332
|
+
for var_name, value in reversed(list(frame.f_locals.items())):
|
|
333
|
+
if id(value) == obj_id:
|
|
334
|
+
return var_name
|
|
335
|
+
|
|
336
|
+
return None
|
|
337
|
+
finally:
|
|
338
|
+
del frame
|
vsview/app/__init__.py
ADDED
|
File without changes
|
vsview/app/error.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import linecache
|
|
2
|
+
from logging import getLogger
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from traceback import TracebackException
|
|
5
|
+
|
|
6
|
+
from PySide6.QtGui import QFontMetrics
|
|
7
|
+
from PySide6.QtWidgets import QGridLayout, QMessageBox, QSpacerItem, QStyle, QWidget
|
|
8
|
+
from vsengine.vpy import ExecutionError
|
|
9
|
+
|
|
10
|
+
from ..assets import get_monospace_font
|
|
11
|
+
from ..vsenv import run_in_loop
|
|
12
|
+
|
|
13
|
+
logger = getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _is_user_script_frame(filename: str, user_script_path: str | None = None) -> bool:
|
|
17
|
+
normalized_filename = filename.lower().replace("\\", "/")
|
|
18
|
+
|
|
19
|
+
if user_script_path:
|
|
20
|
+
normalized_script = user_script_path.lower().replace("\\", "/")
|
|
21
|
+
|
|
22
|
+
if (normalized_filename == normalized_script) or (
|
|
23
|
+
user_script_path.startswith("<") and filename == user_script_path
|
|
24
|
+
):
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
if filename.startswith(("src/cython/", "<")):
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
return not any(
|
|
31
|
+
marker in normalized_filename for marker in ("site-packages/", "/lib/", ".venv/", "venv/", "lib/python")
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _find_user_script_frame(tb: TracebackException, user_script_path: str | None = None) -> tuple[str, int] | None:
|
|
36
|
+
if not tb.stack:
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
# Walk backwards from the last frame to find a user script frame
|
|
40
|
+
for frame in reversed(tb.stack):
|
|
41
|
+
if frame.filename and frame.lineno is not None and _is_user_script_frame(frame.filename, user_script_path):
|
|
42
|
+
return (frame.filename, frame.lineno)
|
|
43
|
+
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@run_in_loop(return_future=False)
|
|
48
|
+
def show_error(error: ExecutionError, parent: QWidget, user_script_path: str | None = None) -> None:
|
|
49
|
+
e = error.parent_error
|
|
50
|
+
|
|
51
|
+
logger.error("Full traceback:", exc_info=e)
|
|
52
|
+
|
|
53
|
+
tb = TracebackException.from_exception(e)
|
|
54
|
+
context = list[str]()
|
|
55
|
+
|
|
56
|
+
# For SyntaxError, get location from the error itself, not the traceback
|
|
57
|
+
# (traceback points to vsengine's compile() call, not the user's script)
|
|
58
|
+
if isinstance(e, SyntaxError) and e.filename is not None and e.lineno is not None:
|
|
59
|
+
filename, lineno = e.filename, e.lineno
|
|
60
|
+
elif result := _find_user_script_frame(tb, user_script_path):
|
|
61
|
+
filename, lineno = result
|
|
62
|
+
else:
|
|
63
|
+
filename, lineno = None, None
|
|
64
|
+
|
|
65
|
+
if filename and lineno:
|
|
66
|
+
# Try reading from real file first, then fall back to linecache (for virtual files)
|
|
67
|
+
if not filename.startswith("<") and (p := Path(filename)).exists():
|
|
68
|
+
lines = p.read_text().splitlines()
|
|
69
|
+
else:
|
|
70
|
+
lines = [line.rstrip("\n\r") for line in linecache.getlines(filename)]
|
|
71
|
+
|
|
72
|
+
if lines:
|
|
73
|
+
context.append(f"File: {filename}:{lineno}")
|
|
74
|
+
|
|
75
|
+
for i in range(max(0, lineno - 4), min(len(lines), lineno + 3)):
|
|
76
|
+
prefix = ">" if i + 1 == lineno else " "
|
|
77
|
+
context.append(f"{prefix}{i + 1:3d} | {lines[i]}")
|
|
78
|
+
else:
|
|
79
|
+
context.append(f"File: {filename}:{lineno}")
|
|
80
|
+
context.append("(source code not available)")
|
|
81
|
+
else:
|
|
82
|
+
context.append("(no traceback information available)")
|
|
83
|
+
|
|
84
|
+
header = f"A {e.__class__.__name__} exception was raised while running the script."
|
|
85
|
+
error_message = f"{header}\n\n{'\n'.join(context)}\n\n{e.__class__.__name__}: {e}\n"
|
|
86
|
+
|
|
87
|
+
font = get_monospace_font()
|
|
88
|
+
metrics = QFontMetrics(font)
|
|
89
|
+
|
|
90
|
+
max_width = max(metrics.horizontalAdvance(line) for line in error_message.splitlines())
|
|
91
|
+
|
|
92
|
+
msg = QMessageBox(parent)
|
|
93
|
+
msg.setIconPixmap(msg.style().standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical).pixmap(48, 48))
|
|
94
|
+
msg.setWindowTitle("Error")
|
|
95
|
+
msg.setText(error_message)
|
|
96
|
+
msg.setFont(font)
|
|
97
|
+
|
|
98
|
+
if isinstance(layout := msg.layout(), QGridLayout):
|
|
99
|
+
spacer = QSpacerItem(max_width, 0)
|
|
100
|
+
layout.addItem(spacer, layout.rowCount(), 0, 1, layout.columnCount())
|
|
101
|
+
|
|
102
|
+
msg.exec()
|