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.
Files changed (425) hide show
  1. vsview/__init__.py +3 -0
  2. vsview/api/__init__.py +87 -0
  3. vsview/api/_helpers.py +53 -0
  4. vsview/api/info.py +6 -0
  5. vsview/api/output.py +338 -0
  6. vsview/app/__init__.py +0 -0
  7. vsview/app/error.py +102 -0
  8. vsview/app/main.py +756 -0
  9. vsview/app/outputs/__init__.py +7 -0
  10. vsview/app/outputs/audio.py +352 -0
  11. vsview/app/outputs/buffer.py +321 -0
  12. vsview/app/outputs/manager.py +154 -0
  13. vsview/app/outputs/packing.py +145 -0
  14. vsview/app/outputs/video.py +166 -0
  15. vsview/app/plugins/__init__.py +27 -0
  16. vsview/app/plugins/_interface.py +517 -0
  17. vsview/app/plugins/api.py +908 -0
  18. vsview/app/plugins/manager.py +259 -0
  19. vsview/app/plugins/specs.py +76 -0
  20. vsview/app/settings/__init__.py +8 -0
  21. vsview/app/settings/dialog.py +472 -0
  22. vsview/app/settings/enums.py +31 -0
  23. vsview/app/settings/manager.py +235 -0
  24. vsview/app/settings/models.py +1473 -0
  25. vsview/app/settings/secrets.py +194 -0
  26. vsview/app/settings/shortcuts.py +237 -0
  27. vsview/app/tools/__init__.py +0 -0
  28. vsview/app/tools/colorpicker/__init__.py +10 -0
  29. vsview/app/tools/colorpicker/plugin.py +504 -0
  30. vsview/app/tools/colorpicker/utils.py +81 -0
  31. vsview/app/tools/cropping/__init__.py +10 -0
  32. vsview/app/tools/cropping/plugin.py +270 -0
  33. vsview/app/tools/cropping/settings.py +61 -0
  34. vsview/app/tools/cropping/utils.py +114 -0
  35. vsview/app/tools/frameprops/__init__.py +11 -0
  36. vsview/app/tools/frameprops/api.py +5 -0
  37. vsview/app/tools/frameprops/builtins/field.py +26 -0
  38. vsview/app/tools/frameprops/builtins/metrics.py +35 -0
  39. vsview/app/tools/frameprops/builtins/video.py +77 -0
  40. vsview/app/tools/frameprops/categories.py +83 -0
  41. vsview/app/tools/frameprops/formatters.py +105 -0
  42. vsview/app/tools/frameprops/plugin.py +711 -0
  43. vsview/app/tools/frameprops/specs.py +22 -0
  44. vsview/app/tools/scening/__init__.py +10 -0
  45. vsview/app/tools/scening/api.py +137 -0
  46. vsview/app/tools/scening/models.py +229 -0
  47. vsview/app/tools/scening/parsers.py +328 -0
  48. vsview/app/tools/scening/plugin.py +762 -0
  49. vsview/app/tools/scening/serializer.py +53 -0
  50. vsview/app/tools/scening/specs.py +22 -0
  51. vsview/app/tools/scening/ui.py +706 -0
  52. vsview/app/tools/scening/utils.py +42 -0
  53. vsview/app/utils.py +183 -0
  54. vsview/app/views/__init__.py +6 -0
  55. vsview/app/views/components.py +392 -0
  56. vsview/app/views/plugins.py +113 -0
  57. vsview/app/views/status.py +319 -0
  58. vsview/app/views/tab.py +220 -0
  59. vsview/app/views/timeline.py +1771 -0
  60. vsview/app/views/video.py +1111 -0
  61. vsview/app/workspace/__init__.py +14 -0
  62. vsview/app/workspace/base.py +74 -0
  63. vsview/app/workspace/file.py +366 -0
  64. vsview/app/workspace/loader.py +826 -0
  65. vsview/app/workspace/playback.py +715 -0
  66. vsview/app/workspace/quick_script.py +501 -0
  67. vsview/app/workspace/tab_manager.py +368 -0
  68. vsview/assets/__init__.py +14 -0
  69. vsview/assets/fonts/Cascadia_Mono/CascadiaMono-Italic-VariableFont_wght.ttf +0 -0
  70. vsview/assets/fonts/Cascadia_Mono/CascadiaMono-VariableFont_wght.ttf +0 -0
  71. vsview/assets/fonts/Cascadia_Mono/LICENSE.txt +94 -0
  72. vsview/assets/icon.png +0 -0
  73. vsview/assets/icons/lucide/LICENSE +39 -0
  74. vsview/assets/icons/lucide/arrow-left.svg +14 -0
  75. vsview/assets/icons/lucide/arrow-right.svg +14 -0
  76. vsview/assets/icons/lucide/check.svg +13 -0
  77. vsview/assets/icons/lucide/circle-x.svg +15 -0
  78. vsview/assets/icons/lucide/clipboard.svg +14 -0
  79. vsview/assets/icons/lucide/fast-forward.svg +14 -0
  80. vsview/assets/icons/lucide/file-code.svg +16 -0
  81. vsview/assets/icons/lucide/file-down.svg +16 -0
  82. vsview/assets/icons/lucide/file-text.svg +17 -0
  83. vsview/assets/icons/lucide/file-up.svg +16 -0
  84. vsview/assets/icons/lucide/file-video-camera.svg +16 -0
  85. vsview/assets/icons/lucide/link-2.svg +15 -0
  86. vsview/assets/icons/lucide/link.svg +14 -0
  87. vsview/assets/icons/lucide/loader-circle.svg +13 -0
  88. vsview/assets/icons/lucide/minus.svg +13 -0
  89. vsview/assets/icons/lucide/move.svg +18 -0
  90. vsview/assets/icons/lucide/panel-right-open.svg +15 -0
  91. vsview/assets/icons/lucide/pause.svg +14 -0
  92. vsview/assets/icons/lucide/pipette.svg +15 -0
  93. vsview/assets/icons/lucide/play.svg +13 -0
  94. vsview/assets/icons/lucide/plus.svg +14 -0
  95. vsview/assets/icons/lucide/rewind.svg +14 -0
  96. vsview/assets/icons/lucide/save.svg +15 -0
  97. vsview/assets/icons/lucide/scan.svg +16 -0
  98. vsview/assets/icons/lucide/search-code.svg +16 -0
  99. vsview/assets/icons/lucide/skip-back.svg +14 -0
  100. vsview/assets/icons/lucide/skip-forward.svg +14 -0
  101. vsview/assets/icons/lucide/square-arrow-right-enter.svg +15 -0
  102. vsview/assets/icons/lucide/square-chevron-left.svg +14 -0
  103. vsview/assets/icons/lucide/square-chevron-right.svg +14 -0
  104. vsview/assets/icons/lucide/square-plus.svg +15 -0
  105. vsview/assets/icons/lucide/undo-2.svg +14 -0
  106. vsview/assets/icons/lucide/unlink-2.svg +13 -0
  107. vsview/assets/icons/lucide/unlink.svg +18 -0
  108. vsview/assets/icons/lucide/volume-1.svg +14 -0
  109. vsview/assets/icons/lucide/volume-2.svg +15 -0
  110. vsview/assets/icons/lucide/volume-off.svg +17 -0
  111. vsview/assets/icons/lucide/volume-x.svg +15 -0
  112. vsview/assets/icons/lucide/volume.svg +13 -0
  113. vsview/assets/icons/material/LICENSE +20 -0
  114. vsview/assets/icons/material/arrow-expand-all.svg +1 -0
  115. vsview/assets/icons/material/arrow-left.svg +1 -0
  116. vsview/assets/icons/material/arrow-right.svg +1 -0
  117. vsview/assets/icons/material/arrow-u-left-top.svg +1 -0
  118. vsview/assets/icons/material/border-radius.svg +1 -0
  119. vsview/assets/icons/material/check-outline.svg +1 -0
  120. vsview/assets/icons/material/check.svg +1 -0
  121. vsview/assets/icons/material/clipboard-outline.svg +1 -0
  122. vsview/assets/icons/material/clipboard.svg +1 -0
  123. vsview/assets/icons/material/close-circle-outline.svg +1 -0
  124. vsview/assets/icons/material/close-circle.svg +1 -0
  125. vsview/assets/icons/material/content-save-outline.svg +1 -0
  126. vsview/assets/icons/material/content-save.svg +1 -0
  127. vsview/assets/icons/material/eyedropper.svg +1 -0
  128. vsview/assets/icons/material/fast-forward-outline.svg +1 -0
  129. vsview/assets/icons/material/fast-forward.svg +1 -0
  130. vsview/assets/icons/material/file-code-outline.svg +1 -0
  131. vsview/assets/icons/material/file-code.svg +1 -0
  132. vsview/assets/icons/material/file-document-outline.svg +1 -0
  133. vsview/assets/icons/material/file-document.svg +1 -0
  134. vsview/assets/icons/material/file-export-outline.svg +1 -0
  135. vsview/assets/icons/material/file-export.svg +1 -0
  136. vsview/assets/icons/material/file-import-outline.svg +1 -0
  137. vsview/assets/icons/material/file-import.svg +1 -0
  138. vsview/assets/icons/material/file-video-outline.svg +1 -0
  139. vsview/assets/icons/material/file-video.svg +1 -0
  140. vsview/assets/icons/material/link-variant-minus.svg +1 -0
  141. vsview/assets/icons/material/link-variant-off.svg +1 -0
  142. vsview/assets/icons/material/link-variant-plus.svg +1 -0
  143. vsview/assets/icons/material/link-variant.svg +1 -0
  144. vsview/assets/icons/material/loading.svg +1 -0
  145. vsview/assets/icons/material/magnify.svg +1 -0
  146. vsview/assets/icons/material/minus.svg +1 -0
  147. vsview/assets/icons/material/page-layout-sidebar-right.svg +1 -0
  148. vsview/assets/icons/material/pause.svg +1 -0
  149. vsview/assets/icons/material/play-outline.svg +1 -0
  150. vsview/assets/icons/material/play.svg +1 -0
  151. vsview/assets/icons/material/plus-box-multiple-outline.svg +1 -0
  152. vsview/assets/icons/material/plus-box-multiple.svg +1 -0
  153. vsview/assets/icons/material/plus-box-outline.svg +1 -0
  154. vsview/assets/icons/material/plus-box.svg +1 -0
  155. vsview/assets/icons/material/plus-outline.svg +1 -0
  156. vsview/assets/icons/material/plus.svg +1 -0
  157. vsview/assets/icons/material/rewind-outline.svg +1 -0
  158. vsview/assets/icons/material/rewind.svg +1 -0
  159. vsview/assets/icons/material/skip-next-outline.svg +1 -0
  160. vsview/assets/icons/material/skip-next.svg +1 -0
  161. vsview/assets/icons/material/skip-previous-outline.svg +1 -0
  162. vsview/assets/icons/material/skip-previous.svg +1 -0
  163. vsview/assets/icons/material/step-backward.svg +1 -0
  164. vsview/assets/icons/material/step-forward.svg +1 -0
  165. vsview/assets/icons/material/volume-high.svg +1 -0
  166. vsview/assets/icons/material/volume-low.svg +1 -0
  167. vsview/assets/icons/material/volume-medium.svg +1 -0
  168. vsview/assets/icons/material/volume-mute.svg +1 -0
  169. vsview/assets/icons/material/volume-off.svg +1 -0
  170. vsview/assets/icons/phosphor/LICENSE +21 -0
  171. vsview/assets/icons/phosphor/arrow-left-bold.svg +1 -0
  172. vsview/assets/icons/phosphor/arrow-left-duotone.svg +1 -0
  173. vsview/assets/icons/phosphor/arrow-left-fill.svg +1 -0
  174. vsview/assets/icons/phosphor/arrow-left-light.svg +1 -0
  175. vsview/assets/icons/phosphor/arrow-left-thin.svg +1 -0
  176. vsview/assets/icons/phosphor/arrow-left.svg +1 -0
  177. vsview/assets/icons/phosphor/arrow-right-bold.svg +1 -0
  178. vsview/assets/icons/phosphor/arrow-right-duotone.svg +1 -0
  179. vsview/assets/icons/phosphor/arrow-right-fill.svg +1 -0
  180. vsview/assets/icons/phosphor/arrow-right-light.svg +1 -0
  181. vsview/assets/icons/phosphor/arrow-right-thin.svg +1 -0
  182. vsview/assets/icons/phosphor/arrow-right.svg +1 -0
  183. vsview/assets/icons/phosphor/arrow-u-up-left-bold.svg +1 -0
  184. vsview/assets/icons/phosphor/arrow-u-up-left-duotone.svg +1 -0
  185. vsview/assets/icons/phosphor/arrow-u-up-left-fill.svg +1 -0
  186. vsview/assets/icons/phosphor/arrow-u-up-left-light.svg +1 -0
  187. vsview/assets/icons/phosphor/arrow-u-up-left-thin.svg +1 -0
  188. vsview/assets/icons/phosphor/arrow-u-up-left.svg +1 -0
  189. vsview/assets/icons/phosphor/arrows-out-cardinal-bold.svg +1 -0
  190. vsview/assets/icons/phosphor/arrows-out-cardinal-duotone.svg +1 -0
  191. vsview/assets/icons/phosphor/arrows-out-cardinal-fill.svg +1 -0
  192. vsview/assets/icons/phosphor/arrows-out-cardinal-light.svg +1 -0
  193. vsview/assets/icons/phosphor/arrows-out-cardinal-thin.svg +1 -0
  194. vsview/assets/icons/phosphor/arrows-out-cardinal.svg +1 -0
  195. vsview/assets/icons/phosphor/check-bold.svg +1 -0
  196. vsview/assets/icons/phosphor/check-duotone.svg +1 -0
  197. vsview/assets/icons/phosphor/check-fill.svg +1 -0
  198. vsview/assets/icons/phosphor/check-light.svg +1 -0
  199. vsview/assets/icons/phosphor/check-thin.svg +1 -0
  200. vsview/assets/icons/phosphor/check.svg +1 -0
  201. vsview/assets/icons/phosphor/clipboard-bold.svg +1 -0
  202. vsview/assets/icons/phosphor/clipboard-duotone.svg +1 -0
  203. vsview/assets/icons/phosphor/clipboard-fill.svg +1 -0
  204. vsview/assets/icons/phosphor/clipboard-light.svg +1 -0
  205. vsview/assets/icons/phosphor/clipboard-thin.svg +1 -0
  206. vsview/assets/icons/phosphor/clipboard.svg +1 -0
  207. vsview/assets/icons/phosphor/eyedropper-bold.svg +1 -0
  208. vsview/assets/icons/phosphor/eyedropper-duotone.svg +1 -0
  209. vsview/assets/icons/phosphor/eyedropper-fill.svg +1 -0
  210. vsview/assets/icons/phosphor/eyedropper-light.svg +1 -0
  211. vsview/assets/icons/phosphor/eyedropper-thin.svg +1 -0
  212. vsview/assets/icons/phosphor/eyedropper.svg +1 -0
  213. vsview/assets/icons/phosphor/fast-forward-bold.svg +1 -0
  214. vsview/assets/icons/phosphor/fast-forward-duotone.svg +1 -0
  215. vsview/assets/icons/phosphor/fast-forward-fill.svg +1 -0
  216. vsview/assets/icons/phosphor/fast-forward-light.svg +1 -0
  217. vsview/assets/icons/phosphor/fast-forward-thin.svg +1 -0
  218. vsview/assets/icons/phosphor/fast-forward.svg +1 -0
  219. vsview/assets/icons/phosphor/file-arrow-down-bold.svg +1 -0
  220. vsview/assets/icons/phosphor/file-arrow-down-duotone.svg +1 -0
  221. vsview/assets/icons/phosphor/file-arrow-down-fill.svg +1 -0
  222. vsview/assets/icons/phosphor/file-arrow-down-light.svg +1 -0
  223. vsview/assets/icons/phosphor/file-arrow-down-thin.svg +1 -0
  224. vsview/assets/icons/phosphor/file-arrow-down.svg +1 -0
  225. vsview/assets/icons/phosphor/file-arrow-up-bold.svg +1 -0
  226. vsview/assets/icons/phosphor/file-arrow-up-duotone.svg +1 -0
  227. vsview/assets/icons/phosphor/file-arrow-up-fill.svg +1 -0
  228. vsview/assets/icons/phosphor/file-arrow-up-light.svg +1 -0
  229. vsview/assets/icons/phosphor/file-arrow-up-thin.svg +1 -0
  230. vsview/assets/icons/phosphor/file-arrow-up.svg +1 -0
  231. vsview/assets/icons/phosphor/file-code-bold.svg +1 -0
  232. vsview/assets/icons/phosphor/file-code-duotone.svg +1 -0
  233. vsview/assets/icons/phosphor/file-code-fill.svg +1 -0
  234. vsview/assets/icons/phosphor/file-code-light.svg +1 -0
  235. vsview/assets/icons/phosphor/file-code-thin.svg +1 -0
  236. vsview/assets/icons/phosphor/file-code.svg +1 -0
  237. vsview/assets/icons/phosphor/file-text-bold.svg +1 -0
  238. vsview/assets/icons/phosphor/file-text-duotone.svg +1 -0
  239. vsview/assets/icons/phosphor/file-text-fill.svg +1 -0
  240. vsview/assets/icons/phosphor/file-text-light.svg +1 -0
  241. vsview/assets/icons/phosphor/file-text-thin.svg +1 -0
  242. vsview/assets/icons/phosphor/file-text.svg +1 -0
  243. vsview/assets/icons/phosphor/file-video-bold.svg +1 -0
  244. vsview/assets/icons/phosphor/file-video-duotone.svg +1 -0
  245. vsview/assets/icons/phosphor/file-video-fill.svg +1 -0
  246. vsview/assets/icons/phosphor/file-video-light.svg +1 -0
  247. vsview/assets/icons/phosphor/file-video-thin.svg +1 -0
  248. vsview/assets/icons/phosphor/file-video.svg +1 -0
  249. vsview/assets/icons/phosphor/floppy-disk-bold.svg +1 -0
  250. vsview/assets/icons/phosphor/floppy-disk-duotone.svg +1 -0
  251. vsview/assets/icons/phosphor/floppy-disk-fill.svg +1 -0
  252. vsview/assets/icons/phosphor/floppy-disk-light.svg +1 -0
  253. vsview/assets/icons/phosphor/floppy-disk-thin.svg +1 -0
  254. vsview/assets/icons/phosphor/floppy-disk.svg +1 -0
  255. vsview/assets/icons/phosphor/frame-corners-bold.svg +1 -0
  256. vsview/assets/icons/phosphor/frame-corners-duotone.svg +1 -0
  257. vsview/assets/icons/phosphor/frame-corners-fill.svg +1 -0
  258. vsview/assets/icons/phosphor/frame-corners-light.svg +1 -0
  259. vsview/assets/icons/phosphor/frame-corners-thin.svg +1 -0
  260. vsview/assets/icons/phosphor/frame-corners.svg +1 -0
  261. vsview/assets/icons/phosphor/link-bold.svg +1 -0
  262. vsview/assets/icons/phosphor/link-break-bold.svg +1 -0
  263. vsview/assets/icons/phosphor/link-break-duotone.svg +1 -0
  264. vsview/assets/icons/phosphor/link-break-fill.svg +1 -0
  265. vsview/assets/icons/phosphor/link-break-light.svg +1 -0
  266. vsview/assets/icons/phosphor/link-break-thin.svg +1 -0
  267. vsview/assets/icons/phosphor/link-break.svg +1 -0
  268. vsview/assets/icons/phosphor/link-duotone.svg +1 -0
  269. vsview/assets/icons/phosphor/link-fill.svg +1 -0
  270. vsview/assets/icons/phosphor/link-light.svg +1 -0
  271. vsview/assets/icons/phosphor/link-simple-horizontal-bold.svg +1 -0
  272. vsview/assets/icons/phosphor/link-simple-horizontal-break-bold.svg +1 -0
  273. vsview/assets/icons/phosphor/link-simple-horizontal-break-duotone.svg +1 -0
  274. vsview/assets/icons/phosphor/link-simple-horizontal-break-fill.svg +1 -0
  275. vsview/assets/icons/phosphor/link-simple-horizontal-break-light.svg +1 -0
  276. vsview/assets/icons/phosphor/link-simple-horizontal-break-thin.svg +1 -0
  277. vsview/assets/icons/phosphor/link-simple-horizontal-break.svg +1 -0
  278. vsview/assets/icons/phosphor/link-simple-horizontal-duotone.svg +1 -0
  279. vsview/assets/icons/phosphor/link-simple-horizontal-fill.svg +1 -0
  280. vsview/assets/icons/phosphor/link-simple-horizontal-light.svg +1 -0
  281. vsview/assets/icons/phosphor/link-simple-horizontal-thin.svg +1 -0
  282. vsview/assets/icons/phosphor/link-simple-horizontal.svg +1 -0
  283. vsview/assets/icons/phosphor/link-thin.svg +1 -0
  284. vsview/assets/icons/phosphor/link.svg +1 -0
  285. vsview/assets/icons/phosphor/magnifying-glass-bold.svg +1 -0
  286. vsview/assets/icons/phosphor/magnifying-glass-duotone.svg +1 -0
  287. vsview/assets/icons/phosphor/magnifying-glass-fill.svg +1 -0
  288. vsview/assets/icons/phosphor/magnifying-glass-light.svg +1 -0
  289. vsview/assets/icons/phosphor/magnifying-glass-thin.svg +1 -0
  290. vsview/assets/icons/phosphor/magnifying-glass.svg +1 -0
  291. vsview/assets/icons/phosphor/minus-bold.svg +1 -0
  292. vsview/assets/icons/phosphor/minus-duotone.svg +1 -0
  293. vsview/assets/icons/phosphor/minus-fill.svg +1 -0
  294. vsview/assets/icons/phosphor/minus-light.svg +1 -0
  295. vsview/assets/icons/phosphor/minus-thin.svg +1 -0
  296. vsview/assets/icons/phosphor/minus.svg +1 -0
  297. vsview/assets/icons/phosphor/pause-bold.svg +1 -0
  298. vsview/assets/icons/phosphor/pause-duotone.svg +1 -0
  299. vsview/assets/icons/phosphor/pause-fill.svg +1 -0
  300. vsview/assets/icons/phosphor/pause-light.svg +1 -0
  301. vsview/assets/icons/phosphor/pause-thin.svg +1 -0
  302. vsview/assets/icons/phosphor/pause.svg +1 -0
  303. vsview/assets/icons/phosphor/play-bold.svg +1 -0
  304. vsview/assets/icons/phosphor/play-duotone.svg +1 -0
  305. vsview/assets/icons/phosphor/play-fill.svg +1 -0
  306. vsview/assets/icons/phosphor/play-light.svg +1 -0
  307. vsview/assets/icons/phosphor/play-thin.svg +1 -0
  308. vsview/assets/icons/phosphor/play.svg +1 -0
  309. vsview/assets/icons/phosphor/plus-bold.svg +1 -0
  310. vsview/assets/icons/phosphor/plus-duotone.svg +1 -0
  311. vsview/assets/icons/phosphor/plus-fill.svg +1 -0
  312. vsview/assets/icons/phosphor/plus-light.svg +1 -0
  313. vsview/assets/icons/phosphor/plus-thin.svg +1 -0
  314. vsview/assets/icons/phosphor/plus.svg +1 -0
  315. vsview/assets/icons/phosphor/rewind-bold.svg +1 -0
  316. vsview/assets/icons/phosphor/rewind-duotone.svg +1 -0
  317. vsview/assets/icons/phosphor/rewind-fill.svg +1 -0
  318. vsview/assets/icons/phosphor/rewind-light.svg +1 -0
  319. vsview/assets/icons/phosphor/rewind-thin.svg +1 -0
  320. vsview/assets/icons/phosphor/rewind.svg +1 -0
  321. vsview/assets/icons/phosphor/selection-background-bold.svg +1 -0
  322. vsview/assets/icons/phosphor/selection-background-duotone.svg +1 -0
  323. vsview/assets/icons/phosphor/selection-background-fill.svg +1 -0
  324. vsview/assets/icons/phosphor/selection-background-light.svg +1 -0
  325. vsview/assets/icons/phosphor/selection-background-thin.svg +1 -0
  326. vsview/assets/icons/phosphor/selection-background.svg +1 -0
  327. vsview/assets/icons/phosphor/selection-bold.svg +1 -0
  328. vsview/assets/icons/phosphor/selection-duotone.svg +1 -0
  329. vsview/assets/icons/phosphor/selection-fill.svg +1 -0
  330. vsview/assets/icons/phosphor/selection-foreground-bold.svg +1 -0
  331. vsview/assets/icons/phosphor/selection-foreground-duotone.svg +1 -0
  332. vsview/assets/icons/phosphor/selection-foreground-fill.svg +1 -0
  333. vsview/assets/icons/phosphor/selection-foreground-light.svg +1 -0
  334. vsview/assets/icons/phosphor/selection-foreground-thin.svg +1 -0
  335. vsview/assets/icons/phosphor/selection-foreground.svg +1 -0
  336. vsview/assets/icons/phosphor/selection-light.svg +1 -0
  337. vsview/assets/icons/phosphor/selection-plus-bold.svg +1 -0
  338. vsview/assets/icons/phosphor/selection-plus-duotone.svg +1 -0
  339. vsview/assets/icons/phosphor/selection-plus-fill.svg +1 -0
  340. vsview/assets/icons/phosphor/selection-plus-light.svg +1 -0
  341. vsview/assets/icons/phosphor/selection-plus-thin.svg +1 -0
  342. vsview/assets/icons/phosphor/selection-plus.svg +1 -0
  343. vsview/assets/icons/phosphor/selection-thin.svg +1 -0
  344. vsview/assets/icons/phosphor/selection.svg +1 -0
  345. vsview/assets/icons/phosphor/sidebar-simple-bold.svg +1 -0
  346. vsview/assets/icons/phosphor/sidebar-simple-duotone.svg +1 -0
  347. vsview/assets/icons/phosphor/sidebar-simple-fill.svg +1 -0
  348. vsview/assets/icons/phosphor/sidebar-simple-light.svg +1 -0
  349. vsview/assets/icons/phosphor/sidebar-simple-thin.svg +1 -0
  350. vsview/assets/icons/phosphor/sidebar-simple.svg +1 -0
  351. vsview/assets/icons/phosphor/skip-back-bold.svg +1 -0
  352. vsview/assets/icons/phosphor/skip-back-duotone.svg +1 -0
  353. vsview/assets/icons/phosphor/skip-back-fill.svg +1 -0
  354. vsview/assets/icons/phosphor/skip-back-light.svg +1 -0
  355. vsview/assets/icons/phosphor/skip-back-thin.svg +1 -0
  356. vsview/assets/icons/phosphor/skip-back.svg +1 -0
  357. vsview/assets/icons/phosphor/skip-forward-bold.svg +1 -0
  358. vsview/assets/icons/phosphor/skip-forward-duotone.svg +1 -0
  359. vsview/assets/icons/phosphor/skip-forward-fill.svg +1 -0
  360. vsview/assets/icons/phosphor/skip-forward-light.svg +1 -0
  361. vsview/assets/icons/phosphor/skip-forward-thin.svg +1 -0
  362. vsview/assets/icons/phosphor/skip-forward.svg +1 -0
  363. vsview/assets/icons/phosphor/speaker-high-bold.svg +1 -0
  364. vsview/assets/icons/phosphor/speaker-high-duotone.svg +1 -0
  365. vsview/assets/icons/phosphor/speaker-high-fill.svg +1 -0
  366. vsview/assets/icons/phosphor/speaker-high-light.svg +1 -0
  367. vsview/assets/icons/phosphor/speaker-high-thin.svg +1 -0
  368. vsview/assets/icons/phosphor/speaker-high.svg +1 -0
  369. vsview/assets/icons/phosphor/speaker-low-bold.svg +1 -0
  370. vsview/assets/icons/phosphor/speaker-low-duotone.svg +1 -0
  371. vsview/assets/icons/phosphor/speaker-low-fill.svg +1 -0
  372. vsview/assets/icons/phosphor/speaker-low-light.svg +1 -0
  373. vsview/assets/icons/phosphor/speaker-low-thin.svg +1 -0
  374. vsview/assets/icons/phosphor/speaker-low.svg +1 -0
  375. vsview/assets/icons/phosphor/speaker-none-bold.svg +1 -0
  376. vsview/assets/icons/phosphor/speaker-none-duotone.svg +1 -0
  377. vsview/assets/icons/phosphor/speaker-none-fill.svg +1 -0
  378. vsview/assets/icons/phosphor/speaker-none-light.svg +1 -0
  379. vsview/assets/icons/phosphor/speaker-none-thin.svg +1 -0
  380. vsview/assets/icons/phosphor/speaker-none.svg +1 -0
  381. vsview/assets/icons/phosphor/speaker-slash-bold.svg +1 -0
  382. vsview/assets/icons/phosphor/speaker-slash-duotone.svg +1 -0
  383. vsview/assets/icons/phosphor/speaker-slash-fill.svg +1 -0
  384. vsview/assets/icons/phosphor/speaker-slash-light.svg +1 -0
  385. vsview/assets/icons/phosphor/speaker-slash-thin.svg +1 -0
  386. vsview/assets/icons/phosphor/speaker-slash.svg +1 -0
  387. vsview/assets/icons/phosphor/speaker-x-bold.svg +1 -0
  388. vsview/assets/icons/phosphor/speaker-x-duotone.svg +1 -0
  389. vsview/assets/icons/phosphor/speaker-x-fill.svg +1 -0
  390. vsview/assets/icons/phosphor/speaker-x-light.svg +1 -0
  391. vsview/assets/icons/phosphor/speaker-x-thin.svg +1 -0
  392. vsview/assets/icons/phosphor/speaker-x.svg +1 -0
  393. vsview/assets/icons/phosphor/spinner-gap-bold.svg +1 -0
  394. vsview/assets/icons/phosphor/spinner-gap-duotone.svg +1 -0
  395. vsview/assets/icons/phosphor/spinner-gap-fill.svg +1 -0
  396. vsview/assets/icons/phosphor/spinner-gap-light.svg +1 -0
  397. vsview/assets/icons/phosphor/spinner-gap-thin.svg +1 -0
  398. vsview/assets/icons/phosphor/spinner-gap.svg +1 -0
  399. vsview/assets/icons/phosphor/x-circle-bold.svg +1 -0
  400. vsview/assets/icons/phosphor/x-circle-duotone.svg +1 -0
  401. vsview/assets/icons/phosphor/x-circle-fill.svg +1 -0
  402. vsview/assets/icons/phosphor/x-circle-light.svg +1 -0
  403. vsview/assets/icons/phosphor/x-circle-thin.svg +1 -0
  404. vsview/assets/icons/phosphor/x-circle.svg +1 -0
  405. vsview/assets/loading.png +0 -0
  406. vsview/assets/providers.py +249 -0
  407. vsview/assets/utils.py +466 -0
  408. vsview/cli.py +240 -0
  409. vsview/env.py +7 -0
  410. vsview/logging.py +103 -0
  411. vsview/py.typed +0 -0
  412. vsview/vsenv/__init__.py +15 -0
  413. vsview/vsenv/gc.py +14 -0
  414. vsview/vsenv/loop.py +253 -0
  415. vsview/vsenv/policy.py +138 -0
  416. vsview-0.1.0.dist-info/METADATA +79 -0
  417. vsview-0.1.0.dist-info/RECORD +425 -0
  418. vsview-0.1.0.dist-info/WHEEL +4 -0
  419. vsview-0.1.0.dist-info/entry_points.txt +2 -0
  420. vsview-0.1.0.dist-info/licenses/LICENSE +291 -0
  421. vsview-0.1.0.dist-info/licenses/src/vsview/assets/fonts/Cascadia_Mono/LICENSE.txt +94 -0
  422. vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/lucide/LICENSE +39 -0
  423. vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/material/LICENSE +20 -0
  424. vsview-0.1.0.dist-info/licenses/src/vsview/assets/icons/phosphor/LICENSE +21 -0
  425. vsview-0.1.0.dist-info/sboms/sboms.json +357 -0
vsview/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .api import catch_output, is_preview, set_output
2
+
3
+ __all__ = ["catch_output", "is_preview", "set_output"]
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
@@ -0,0 +1,6 @@
1
+ import sys
2
+
3
+
4
+ def is_preview() -> bool:
5
+ """Check if the current script is running in a preview environment (VSView only)."""
6
+ return bool(sys.modules.get("__vsview__"))
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()