13 Commits

Author SHA1 Message Date
df6f215514 Merge pull request #18 from onyx-and-iris/dependabot/pip/black-24.3.0
Bump black from 22.12.0 to 24.3.0
2024-03-28 16:10:04 +00:00
dependabot[bot]
0a5987631f Bump black from 22.12.0 to 24.3.0
Bumps [black](https://github.com/psf/black) from 22.12.0 to 24.3.0.
- [Release notes](https://github.com/psf/black/releases)
- [Changelog](https://github.com/psf/black/blob/main/CHANGES.md)
- [Commits](https://github.com/psf/black/compare/22.12.0...24.3.0)

---
updated-dependencies:
- dependency-name: black
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-28 16:09:32 +00:00
3d3bc71d15 upd rewriter to reflect changes to pyinstaller 2024-01-30 15:07:20 +00:00
7b148b2614 upd build dep pyinstaller 2024-01-30 14:11:13 +00:00
ef558fdde6 dependency updates 2024-01-30 11:09:15 +00:00
c684ed9981 should a config be loaded during engine startup
bypass _base_values.run_update

patch bump
2023-09-07 08:39:20 +01:00
1498daf36f refactor 2023-08-28 05:17:54 +01:00
e964c94d07 update dependency groups 2023-08-27 18:42:26 +01:00
9f20225a59 build scripts added 2023-08-27 02:41:07 +01:00
f63c36c94a add poetry badge to readme 2023-08-19 19:58:27 +01:00
c2db0f2757 dependencies updated.
patch bump
2023-08-06 23:16:20 +01:00
bfb0482c32 on_close_window() callback added.
cleanly shuts down vban connection on windows close
if vban connected.
2023-08-06 23:15:54 +01:00
6222ab1e62 id renamed to identifier in _make_channelframe()
label_cache arrays now initialised with empty strings

update_levels() now called when initialising ChannelFrame
2023-08-06 23:15:08 +01:00
11 changed files with 570 additions and 73 deletions

7
.gitignore vendored
View File

@@ -132,4 +132,11 @@ dmypy.json
# Pyre type checker # Pyre type checker
.pyre/ .pyre/
# build
sv_ttk/
theme/
sv_*.py
fst_*.py
.vscode/ .vscode/

View File

@@ -1,5 +1,6 @@
[![PyPI version](https://badge.fury.io/py/voicemeeter-compact.svg)](https://badge.fury.io/py/voicemeeter-compact) [![PyPI version](https://badge.fury.io/py/voicemeeter-compact.svg)](https://badge.fury.io/py/voicemeeter-compact)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/onyx-and-iris/voicemeeter-compact/blob/main/LICENSE) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/onyx-and-iris/voicemeeter-compact/blob/main/LICENSE)
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
![OS: Windows](https://img.shields.io/badge/os-windows-red) ![OS: Windows](https://img.shields.io/badge/os-windows-red)

40
build.ps1 Normal file
View File

@@ -0,0 +1,40 @@
param(
[Parameter(Mandatory = $true)]
[string]$prefix,
[string]$theme
)
function Format-Path {
param($Kind)
return @(
$prefix,
(& { if ($theme) { $theme } else { "" } }),
"${Kind}"
).Where({ $_ -ne "" }) -Join "_"
}
function Compress-Builds {
$target = Join-Path -Path $PSScriptRoot -ChildPath "dist"
@("basic", "banana", "potato") | ForEach-Object {
$compress_path = Format-Path -Kind $_
Compress-Archive -Path $(Join-Path -Path $target -ChildPath $compress_path) -DestinationPath $(Join-Path -Path $target -ChildPath "${compress_path}.zip") -Force
}
}
function Get-Builds {
@("basic", "banana", "potato") | ForEach-Object {
$spec_path = Format-Path -Kind $_
"building $spec_path" | Write-Host
poetry run pyinstaller "$spec_path.spec" --noconfirm
}
}
function main {
Get-Builds
Compress-Builds
}
if ($MyInvocation.InvocationName -ne '.') { main }

198
poetry.lock generated
View File

@@ -1,36 +1,59 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. # This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
[[package]]
name = "altgraph"
version = "0.17.3"
description = "Python graph (network) package"
optional = false
python-versions = "*"
files = [
{file = "altgraph-0.17.3-py2.py3-none-any.whl", hash = "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe"},
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
]
[[package]] [[package]]
name = "black" name = "black"
version = "22.12.0" version = "24.3.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"},
{file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"},
{file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"},
{file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"},
{file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"},
{file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"},
{file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"},
{file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"},
{file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"},
{file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"},
{file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"},
{file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"},
{file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"},
{file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"},
{file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"},
{file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"},
{file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"},
{file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"},
{file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"},
{file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"},
{file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"},
{file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"},
] ]
[package.dependencies] [package.dependencies]
click = ">=8.0.0" click = ">=8.0.0"
mypy-extensions = ">=0.4.3" mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0" pathspec = ">=0.9.0"
platformdirs = ">=2" platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
[package.extras] [package.extras]
colorama = ["colorama (>=0.4.3)"] colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"] d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"] uvloop = ["uvloop (>=0.15.2)"]
@@ -76,6 +99,20 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"
plugins = ["setuptools"] plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"] requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]]
name = "macholib"
version = "1.16.2"
description = "Mach-O header analysis and editing"
optional = false
python-versions = "*"
files = [
{file = "macholib-1.16.2-py2.py3-none-any.whl", hash = "sha256:44c40f2cd7d6726af8fa6fe22549178d3a4dfecc35a9cd15ea916d9c83a688e0"},
{file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"},
]
[package.dependencies]
altgraph = ">=0.17"
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
@@ -87,6 +124,17 @@ files = [
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
] ]
[[package]]
name = "packaging"
version = "23.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
]
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.11.1" version = "0.11.1"
@@ -98,6 +146,17 @@ files = [
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
] ]
[[package]]
name = "pefile"
version = "2023.2.7"
description = "Python PE parsing module"
optional = false
python-versions = ">=3.6.0"
files = [
{file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"},
{file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"},
]
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.8.1" version = "3.8.1"
@@ -113,15 +172,87 @@ files = [
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
[[package]]
name = "pyinstaller"
version = "6.3.0"
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
optional = false
python-versions = "<3.13,>=3.8"
files = [
{file = "pyinstaller-6.3.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:75a6f2a6f835a2e6e0899d10e60c10caf5defd25aced38b1dd48fbbabc89de07"},
{file = "pyinstaller-6.3.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:de25beb176f73a944758553caacec46cc665bf3910ad8a174706d79cf6e95340"},
{file = "pyinstaller-6.3.0-py3-none-manylinux2014_i686.whl", hash = "sha256:e436fcc0ea87c3f132baac916d508c24c84a8f6d8a06c3154fbc753f169b76c7"},
{file = "pyinstaller-6.3.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:b721d793a33b6d9946c7dd95d3ea7589c0424b51cf1b9fe580f03c544f1336b2"},
{file = "pyinstaller-6.3.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:96c37a1ee5b2fd5bb25c098ef510661d6d17b6515d0b86d8fc93727dd2475ba3"},
{file = "pyinstaller-6.3.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:abe91106a3bbccc3f3a27af4325676ecdb6f46cb842ac663625002a870fc503b"},
{file = "pyinstaller-6.3.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:41c937fe8f07ae02009b3b5a96ac3eb0800a4f8a97af142d4100060fe2135bb9"},
{file = "pyinstaller-6.3.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:886b3b995b674905a20ad5b720b47cc395897d7b391117831027a4c8c5d67a58"},
{file = "pyinstaller-6.3.0-py3-none-win32.whl", hash = "sha256:0597fb04337695e5cc5250253e0655530bf14f264b7a5b7d219cc65f6889c4bd"},
{file = "pyinstaller-6.3.0-py3-none-win_amd64.whl", hash = "sha256:156b32ba943e0090bcc68e40ae1cb68fd92b7f1ab6fe0bdf8faf3d3cfc4e12dd"},
{file = "pyinstaller-6.3.0-py3-none-win_arm64.whl", hash = "sha256:1eadbd1fae84e2e6c678d8b4ed6a232ec5c8fe3a839aea5a3071c4c0282f98cc"},
{file = "pyinstaller-6.3.0.tar.gz", hash = "sha256:914d4c96cc99472e37ac552fdd82fbbe09e67bb592d0717fcffaa99ea74273df"},
]
[package.dependencies]
altgraph = "*"
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
packaging = ">=22.0"
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
pyinstaller-hooks-contrib = ">=2021.4"
pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
setuptools = ">=42.0.0"
[package.extras]
completion = ["argcomplete"]
hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
[[package]]
name = "pyinstaller-hooks-contrib"
version = "2023.7"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyinstaller-hooks-contrib-2023.7.tar.gz", hash = "sha256:0c436a4c3506020e34116a8a7ddfd854c1ad6ddca9a8cd84500bd6e69c9e68f9"},
{file = "pyinstaller_hooks_contrib-2023.7-py2.py3-none-any.whl", hash = "sha256:3c10df14c0f71ab388dfbf1625375b087e7330d9444cbfd2b310ba027fa0cff0"},
]
[[package]]
name = "pywin32-ctypes"
version = "0.2.2"
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
optional = false
python-versions = ">=3.6"
files = [
{file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
{file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
]
[[package]]
name = "setuptools"
version = "68.1.2"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"},
{file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"},
]
[package.extras]
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]] [[package]]
name = "sv-ttk" name = "sv-ttk"
version = "2.5.3" version = "2.5.5"
description = "A gorgeous theme for Tkinter, based on Windows 11's UI" description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "sv_ttk-2.5.3-py3-none-any.whl", hash = "sha256:d13bf6a7b49316431eefcf83f30d0daf312c00553c4e0b6f91acffd7b2aaa1d3"}, {file = "sv_ttk-2.5.5-py3-none-any.whl", hash = "sha256:49d1cd03c032728c183d1fe2318f88cdb658ef3e87157e1ca3fcf6661054965b"},
{file = "sv_ttk-2.5.3.tar.gz", hash = "sha256:d9b9a5d14f4cbdd4e0bda2e1a84445b0aa852b99f74aafce9386459e385717b3"}, {file = "sv_ttk-2.5.5.tar.gz", hash = "sha256:9bbfe2aba6cc6f9fdf70d79331046543c9666fcccc78bad5ff648a9987e3cedb"},
] ]
[[package]] [[package]]
@@ -135,15 +266,26 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
[[package]]
name = "typing-extensions"
version = "4.10.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
]
[[package]] [[package]]
name = "vban-cmd" name = "vban-cmd"
version = "2.3.2" version = "2.4.11"
description = "Python interface for the VBAN RT Packet Service (Sendtext)" description = "Python interface for the VBAN RT Packet Service (Sendtext)"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
files = [ files = [
{file = "vban_cmd-2.3.2-py3-none-any.whl", hash = "sha256:28168a7ec1c6966fd4bcbaed3144219f8cdc2490f15dd8ecba2aa19f2a3461f5"}, {file = "vban_cmd-2.4.11-py3-none-any.whl", hash = "sha256:a74b7631222f340488f5d45bc9aa9d4e7a0f919687c9715619e8809c684875b7"},
{file = "vban_cmd-2.3.2.tar.gz", hash = "sha256:c33e338e3207f35a6b9f9026d29cf68af9e5f6d7c96aea4b581225f4befd844e"}, {file = "vban_cmd-2.4.11.tar.gz", hash = "sha256:250ca8043f075eee11d2a811142d0205900d14d7e2f0cd98eb597901ead738f5"},
] ]
[package.dependencies] [package.dependencies]
@@ -151,13 +293,13 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[[package]] [[package]]
name = "voicemeeter-api" name = "voicemeeter-api"
version = "2.3.2" version = "2.5.3"
description = "A Python wrapper for the Voiceemeter API" description = "A Python wrapper for the Voiceemeter API"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
files = [ files = [
{file = "voicemeeter_api-2.3.2-py3-none-any.whl", hash = "sha256:081bd6b3e27d8757e4c5ed239b4c58f9bcb4f4d16ebc9c88229e9390dac184c8"}, {file = "voicemeeter_api-2.5.3-py3-none-any.whl", hash = "sha256:00c1f5b4027844d09ae19042f1662501dc28b1cee12a4238503790a50293c8f7"},
{file = "voicemeeter_api-2.3.2.tar.gz", hash = "sha256:aa700600b5910e4bb55df20cdf028aae2a44cc14bfd80dd0fe060aa03bbf7e02"}, {file = "voicemeeter_api-2.5.3.tar.gz", hash = "sha256:b40f77e94446b4a5ab561c777109bdaf9c2478dfaa19e728c91ade3b44226704"},
] ]
[package.dependencies] [package.dependencies]
@@ -165,5 +307,5 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = ">=3.10,<3.13"
content-hash = "770291c3645dd9bfd28051c0deb13bf5ae17a510bfc2785b51be1bc5c7266b1a" content-hash = "e0fbc41a1fa7dbdd4f13cb645f2a1a824726741b9afcc3f08429baedeb60d924"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "voicemeeter-compact" name = "voicemeeter-compact"
version = "1.9.1" version = "1.9.4"
description = "A Compact Voicemeeter Remote App" description = "A Compact Voicemeeter Remote App"
authors = ["onyx-and-iris <code@onyxandiris.online>"] authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT" license = "MIT"
@@ -11,16 +11,25 @@ packages = [{ include = "vmcompact" }]
include = ["vmcompact/img/cat.ico"] include = ["vmcompact/img/cat.ico"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = ">=3.10,<3.13"
sv-ttk = "^2.5.1" sv-ttk = "^2.5.5"
tomli = { version = "^2.0.1", python = "<3.11" } tomli = { version = "^2.0.1", python = "<3.11" }
voicemeeter-api = "^2.3.2" voicemeeter-api = "^2.5.3"
vban-cmd = "^2.3.2" vban-cmd = "^2.4.11"
[tool.poetry.dev-dependencies] [tool.poetry.group.dev.dependencies]
black = { version = "^22.6.0", allow-prereleases = true } black = { version = ">=22.6,<25.0", allow-prereleases = true }
isort = "^5.12.0" isort = "^5.12.0"
[tool.poetry.group.build.dependencies]
pyinstaller = "^6.3.0"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
build_sunvalley = "scripts:build_sunvalley"
build_forest = "scripts:build_forest"
build_all = "scripts:build_all"

24
scripts.py Normal file
View File

@@ -0,0 +1,24 @@
import subprocess
import sys
from pathlib import Path
def build_sunvalley():
buildscript = Path.cwd() / "build.ps1"
subprocess.run(["powershell", str(buildscript), "sv"])
def build_forest():
rewriter = Path.cwd() / "tools" / "rewriter.py"
subprocess.run([sys.executable, str(rewriter), "-r"])
buildscript = Path.cwd() / "build.ps1"
for theme in ("light", "dark"):
subprocess.run(["powershell", str(buildscript), "fst", theme])
subprocess.run([sys.executable, str(rewriter), "-c"])
def build_all():
steps = (build_sunvalley, build_forest)
[step() for step in steps]

250
tools/rewriter.py Normal file
View File

@@ -0,0 +1,250 @@
import argparse
import logging
from pathlib import Path
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("vm-compact-rewriter")
PACKAGE_DIR = Path(__file__).parent.parent / "vmcompact"
SRC_DIR = Path(__file__).parent / "src"
def write_outs(output, outs: tuple):
for out in outs:
output.write(out)
def rewrite_app():
app_logger = logger.getChild("app")
app_logger.info("rewriting app.py")
infile = Path(SRC_DIR) / "app.bk"
outfile = Path(PACKAGE_DIR) / "app.py"
with open(infile, "r") as input:
with open(outfile, "w") as output:
for line in input:
match line:
# App init()
case " def __init__(self, vmr):\n":
output.write(" def __init__(self, vmr, theme):\n")
case " self._vmr = vmr\n":
write_outs(
output,
(
" self._vmr = vmr\n",
" self._theme = theme\n",
' tcldir = Path.cwd() / "theme"\n',
" if not tcldir.is_dir():\n",
' tcldir = Path.cwd() / "_internal" / "theme"\n',
' self.tk.call("source", tcldir.resolve() / f"forest-{self._theme}.tcl")\n',
),
)
# def connect()
case "def connect(kind_id: str, vmr) -> App:\n":
output.write(
'def connect(kind_id: str, vmr, theme="light") -> App:\n'
)
case " return VMMIN_cls(vmr)\n":
output.write(" return VMMIN_cls(vmr, theme)\n")
case _:
output.write(line)
def rewrite_builders():
builders_logger = logger.getChild("builders")
builders_logger.info("rewriting builders.py")
infile = Path(SRC_DIR) / "builders.bk"
outfile = Path(PACKAGE_DIR) / "builders.py"
with open(infile, "r") as input:
with open(outfile, "w") as output:
ignore_next_lines = 0
for line in input:
if ignore_next_lines > 0:
builders_logger.info(f"ignoring: {line}")
ignore_next_lines -= 1
continue
match line:
# loading themes
case "import sv_ttk\n":
output.write("#import sv_ttk\n")
case " self.app.resizable(False, False)\n":
write_outs(
output,
(
" self.app.resizable(False, False)\n"
" if _configuration.themes_enabled:\n",
' ttk.Style().theme_use(f"forest-{self.app._theme}")\n',
' self.logger.info(f"Forest Theme applied")\n',
),
)
ignore_next_lines = 6
# setting navframe button widths
case " variable=self.navframe.submix,\n":
write_outs(
output,
(
" variable=self.navframe.submix,\n"
" width=8,\n",
),
)
case " variable=self.navframe.channel,\n":
write_outs(
output,
(
" variable=self.navframe.channel,\n"
" width=8,\n",
),
)
case " variable=self.navframe.extend,\n":
write_outs(
output,
(
" variable=self.navframe.extend,\n"
" width=8,\n",
),
)
case " variable=self.navframe.info,\n":
write_outs(
output,
(
" variable=self.navframe.info,\n"
" width=8,\n",
),
)
# set channelframe button widths
case " variable=self.labelframe.mute,\n":
write_outs(
output,
(
" variable=self.labelframe.mute,\n"
" width=7,\n",
),
)
case " variable=self.labelframe.conf,\n":
write_outs(
output,
(
" variable=self.labelframe.conf,\n"
" width=7,\n",
),
)
case " variable=self.labelframe.on,\n":
write_outs(
output,
(
" variable=self.labelframe.on,\n"
" width=7,\n",
),
)
# set stripconfigframe button widths
case " self.configframe.phys_out_params.index(param)\n":
write_outs(
output,
(
" self.configframe.phys_out_params.index(param)\n",
" ],\n",
" width=6,\n",
),
)
ignore_next_lines = 1
case " self.configframe.virt_out_params.index(param)\n":
write_outs(
output,
(
" self.configframe.virt_out_params.index(param)\n",
" ],\n",
" width=6,\n",
),
)
ignore_next_lines = 1
# This does both strip and bus param vars buttons
case " variable=self.configframe.param_vars[i],\n":
write_outs(
output,
(
" variable=self.configframe.param_vars[i],\n",
" width=6,\n",
),
)
case _:
if "Toggle.TButton" in line:
output.write(line.replace("Toggle.TButton", "ToggleButton"))
else:
output.write(line)
def rewrite_menu():
menu_logger = logger.getChild("menu")
menu_logger.info("rewriting menu.py")
infile = Path(SRC_DIR) / "menu.bk"
outfile = Path(PACKAGE_DIR) / "menu.py"
with open(infile, "r") as input:
with open(outfile, "w") as output:
ignore_next_lines = 0
for line in input:
if ignore_next_lines > 0:
menu_logger.info(f"ignoring: {line}")
ignore_next_lines -= 1
continue
match line:
case "import sv_ttk\n":
output.write("#import sv_ttk\n")
case " # layout/themes\n":
ignore_next_lines = 14
case _:
output.write(line)
def prepare_for_build():
################# MOVE FILES FROM PACKAGE DIR INTO SRC DIR #########################
for file in (
PACKAGE_DIR / "app.py",
PACKAGE_DIR / "builders.py",
PACKAGE_DIR / "menu.py",
):
if file.exists():
logger.debug(f"moving {str(file)}")
file.rename(SRC_DIR / f"{file.stem}.bk")
###################### RUN THE FILE REWRITER FOR EACH *.BK #########################
steps = (
rewrite_app,
rewrite_builders,
rewrite_menu,
)
[step() for step in steps]
def cleanup():
########################## RESTORE *.BK FILES #####################################
for file in (
PACKAGE_DIR / "app.py",
PACKAGE_DIR / "builders.py",
PACKAGE_DIR / "menu.py",
):
file.unlink()
for file in (
SRC_DIR / "app.bk",
SRC_DIR / "builders.bk",
SRC_DIR / "menu.bk",
):
file.rename(PACKAGE_DIR / f"{file.stem}.py")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("-r", "--rewrite", action="store_true")
parser.add_argument("-c", "--cleanup", action="store_true")
args = parser.parse_args()
if args.rewrite:
logger.info("preparing files for build")
prepare_for_build()
elif args.cleanup:
logger.info("cleaning up files")
cleanup()

0
tools/src/.gitkeep Normal file
View File

View File

@@ -42,14 +42,15 @@ class App(tk.Tk):
self.logger = logger.getChild(self.__class__.__name__) self.logger = logger.getChild(self.__class__.__name__)
self._vmr = vmr self._vmr = vmr
self._vmr.event.add(["pdirty", "ldirty"]) self._vmr.event.add(["pdirty", "ldirty"])
self.after(12000 if self._vmr.gui.launched_by_api else 1, self.start_updates) self.subject = Subject()
self.start_updates()
self._vmr.init_thread() self._vmr.init_thread()
icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico" icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico"
if icon_path.is_file(): if icon_path.is_file():
self.iconbitmap(str(icon_path)) self.iconbitmap(str(icon_path))
self.minsize(275, False) self.minsize(275, False)
self.subject = Subject()
self._configs = None self._configs = None
self.protocol("WM_DELETE_WINDOW", self.on_close_window)
self.menu = self["menu"] = Menus(self, vmr) self.menu = self["menu"] = Menus(self, vmr)
self.styletable = ttk.Style() self.styletable = ttk.Style()
if _configuration.config: if _configuration.config:
@@ -147,10 +148,15 @@ class App(tk.Tk):
return self._configs return self._configs
def start_updates(self): def start_updates(self):
self.logger.debug("updates started") def init():
_base_values.run_update = True self.logger.debug("updates started")
_base_values.run_update = True
if self._vmr.gui.launched_by_api: if self._vmr.gui.launched_by_api:
self.on_pdirty() self.subject.notify("pdirty")
self.after(12000, init)
else:
init()
def healthcheck_step(self): def healthcheck_step(self):
if not _base_values.vban_connected: if not _base_values.vban_connected:
@@ -182,6 +188,11 @@ class App(tk.Tk):
self.destroy() self.destroy()
self.after(250, self.healthcheck_step) self.after(250, self.healthcheck_step)
def on_close_window(self):
if _base_values.vban_connected:
self._vban.logout()
self.destroy()
_apps = {kind.name: App.make(kind) for kind in _kinds_all} _apps = {kind.name: App.make(kind) for kind in _kinds_all}

View File

@@ -151,17 +151,18 @@ class ChannelLabelFrame(ttk.LabelFrame):
def sync_labels(self): def sync_labels(self):
"""sync labelframes according to label text""" """sync labelframes according to label text"""
retval = self.getter("label") retval = self.getter("label")
self.parent.label_cache[self.id].insert(self.index, retval) if self.parent.label_cache[self.id][self.index] != retval:
if len(retval) > 10: self.parent.label_cache[self.id][self.index] = retval
retval = f"{retval[:8]}.." if len(retval) > 10:
if not retval: retval = f"{retval[:8]}.."
self.parent.columnconfigure(self.index, minsize=0) if not retval:
self.parent.parent.subject.remove(self) self.parent.columnconfigure(self.index, minsize=0)
self.grid_remove() self.parent.parent.subject.remove(self)
else: self.grid_remove()
self.parent.parent.subject.add(self) else:
self.grid() self.parent.parent.subject.add(self)
self.configure(text=retval) self.grid()
self.configure(text=retval)
def grid_configure(self): def grid_configure(self):
self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S)) self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S))
@@ -228,15 +229,18 @@ class Bus(ChannelLabelFrame):
class ChannelFrame(ttk.Frame): class ChannelFrame(ttk.Frame):
label_cache = {"strip": list(), "bus": list()}
def init(self, parent, id): def init(self, parent, id):
super().__init__(parent) super().__init__(parent)
self.parent = parent self.parent = parent
self.id = id self.id = id
self.phys_in, self.virt_in = parent.kind.ins self.phys_in, self.virt_in = parent.kind.ins
self.phys_out, self.virt_out = parent.kind.outs self.phys_out, self.virt_out = parent.kind.outs
self.label_cache = {
"strip": [""] * (self.phys_in + self.virt_in),
"bus": [""] * (self.phys_out + self.virt_out),
}
self.parent.subject.add(self) self.parent.subject.add(self)
self.update_labels()
@property @property
def target(self): def target(self):
@@ -258,13 +262,13 @@ class ChannelFrame(ttk.Frame):
if isinstance(frame, ttk.LabelFrame) if isinstance(frame, ttk.LabelFrame)
) )
def update_labels(self):
for labelframe in self.labelframes:
labelframe.on_update("labelframe")
def on_update(self, subject): def on_update(self, subject):
if subject == "pdirty": if subject == "pdirty":
target = getattr(self.target, self.id) self.update_labels()
num = getattr(self.parent.kind, f"num_{self.id}")
if self.label_cache[self.id] != [target[i].label for i in range(num)]:
for labelframe in self.labelframes:
labelframe.on_update("labelframe")
def grid_configure(self): def grid_configure(self):
[ [
@@ -280,7 +284,7 @@ class ChannelFrame(ttk.Frame):
setattr(self.parent, f"{self.identifier}_frame", None) setattr(self.parent, f"{self.identifier}_frame", None)
def _make_channelframe(parent, id): def _make_channelframe(parent, identifier):
""" """
Creates a Channel Frame class of type strip or bus Creates a Channel Frame class of type strip or bus
""" """
@@ -288,29 +292,33 @@ def _make_channelframe(parent, id):
phys_in, virt_in = parent.kind.ins phys_in, virt_in = parent.kind.ins
phys_out, virt_out = parent.kind.outs phys_out, virt_out = parent.kind.outs
def init_labels(self, id): def init_labels(self):
""" """
Grids each labelframe, grid_removes any without a label Grids each labelframe, grid_removes any without a label
""" """
for i, labelframe in enumerate( for i, labelframe in enumerate(
getattr(self, "strips" if id == "strip" else "buses") getattr(self, "strips" if identifier == "strip" else "buses")
): ):
labelframe.grid(row=0, column=i) labelframe.grid(row=0, column=i)
if not labelframe.target.label: label = labelframe.target.label
if not label:
self.columnconfigure(i, minsize=0) self.columnconfigure(i, minsize=0)
labelframe.grid_remove() labelframe.grid_remove()
self.label_cache[identifier][i] = label
def init_strip(self, *args, **kwargs): def init_strip(self, *args, **kwargs):
self.init(parent, id) self.init(parent, identifier)
self.strips = tuple(Strip(self, i, id) for i in range(phys_in + virt_in)) self.strips = tuple(
Strip(self, i, identifier) for i in range(phys_in + virt_in)
)
self.grid(row=0, column=0, sticky=(tk.W)) self.grid(row=0, column=0, sticky=(tk.W))
self.grid_configure() self.grid_configure()
init_labels(self, id) init_labels(self)
def init_bus(self, *args, **kwargs): def init_bus(self, *args, **kwargs):
self.init(parent, id) self.init(parent, identifier)
self.buses = tuple(Bus(self, i, id) for i in range(phys_out + virt_out)) self.buses = tuple(Bus(self, i, identifier) for i in range(phys_out + virt_out))
if _configuration.extended: if _configuration.extended:
if _configuration.extends_horizontal: if _configuration.extends_horizontal:
self.grid(row=0, column=2, sticky=(tk.W)) self.grid(row=0, column=2, sticky=(tk.W))
@@ -319,11 +327,11 @@ def _make_channelframe(parent, id):
else: else:
self.grid(row=0, column=0) self.grid(row=0, column=0)
self.grid_configure() self.grid_configure()
init_labels(self, id) init_labels(self)
if id == "strip": if identifier == "strip":
CHANNELFRAME_cls = type( CHANNELFRAME_cls = type(
f"ChannelFrame{id.capitalize()}", f"ChannelFrame{identifier.capitalize()}",
(ChannelFrame,), (ChannelFrame,),
{ {
"__init__": init_strip, "__init__": init_strip,
@@ -331,7 +339,7 @@ def _make_channelframe(parent, id):
) )
else: else:
CHANNELFRAME_cls = type( CHANNELFRAME_cls = type(
f"ChannelFrame{id.capitalize()}", f"ChannelFrame{identifier.capitalize()}",
(ChannelFrame,), (ChannelFrame,),
{ {
"__init__": init_bus, "__init__": init_bus,

View File

@@ -4,10 +4,11 @@ import webbrowser
from functools import partial from functools import partial
from tkinter import messagebox from tkinter import messagebox
import sv_ttk
import vban_cmd import vban_cmd
from vban_cmd.error import VBANCMDConnectionError from vban_cmd.error import VBANCMDConnectionError
import sv_ttk
from .data import _base_values, _configuration, get_configuration, kind_get from .data import _base_values, _configuration, get_configuration, kind_get
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -227,7 +228,7 @@ class Menus(tk.Menu):
if fn := getattr(self.target.command, cmd): if fn := getattr(self.target.command, cmd):
fn() fn()
if cmd == "shutdown": if cmd == "shutdown":
self.parent.destroy() self.parent.on_close_window()
def action_set_voicemeeter(self, cmd, val=True): def action_set_voicemeeter(self, cmd, val=True):
if cmd == "lock": if cmd == "lock":
@@ -238,10 +239,14 @@ class Menus(tk.Menu):
def load_custom_profile(self, profile): def load_custom_profile(self, profile):
self.logger.info(f"loading user profile {profile}") self.logger.info(f"loading user profile {profile}")
self.target.apply(profile) self.target.apply(profile)
if not _base_values.run_update:
self.parent.subject.notify("pdirty")
def load_profile(self, profile): def load_profile(self, profile):
self.logger.info(f"loading user profile {profile}") self.logger.info(f"loading user profile {profile}")
self.target.apply_config(profile) self.target.apply_config(profile)
if not _base_values.run_update:
self.parent.subject.notify("pdirty")
def load_defaults(self): def load_defaults(self):
msg = ( msg = (