15 Commits

Author SHA1 Message Date
c3f20ea43f patch bump 2024-07-03 07:57:21 +01:00
2e868705d5 bump dependencies 2024-07-02 22:24:51 +01:00
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 602 additions and 101 deletions

7
.gitignore vendored
View File

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

View File

@@ -1,5 +1,6 @@
[![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)
[![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)
![OS: Windows](https://img.shields.io/badge/os-windows-red)
@@ -109,7 +110,7 @@ Configure certain startup states for the app.
Configure a user config to load on app startup. Don't include the .toml extension in the config name.
- `theme`
By default the app loads up the [Sun Valley light or dark theme](https://github.com/rdbende/Sun-Valley-ttk-theme) by @rdbende. You have the option to load up the app without any theme loaded. Simply set `enabled` to false and `mode` will take no effect.
By default the app loads up the [Sun Valley light or dark theme][def] by @rdbende. You have the option to load up the app without any theme loaded. Simply set `enabled` to false and `mode` will take no effect.
- `extends`
Extending the app will show both strips and buses. In reduced mode only one or the other. This app will extend both horizontally and vertically, simply set `extends_horizontal` true or false accordingly.
@@ -149,7 +150,7 @@ port = 6990
Three example user configs are included with the package, one for each kind of Voicemeeter. Use these to configure parameter startup states. Any parameter supported by the underlying interfaces may be used. Check the 'multiple-parameters' section for more info:
[Python Interface for Voicemeeter API](https://github.com/onyx-and-iris/voicemeeter-api-python#multiple-parameters)
[Python Interface for the Voicemeeter API](https://github.com/onyx-and-iris/voicemeeter-api-python#multiple-parameters)
[Python Interface for VBAN CMD](https://github.com/onyx-and-iris/vban-cmd-python#multiple-parameters)
@@ -157,6 +158,9 @@ User configs may be loaded at any time via the menu.
## Special Thanks
[Vincent Burel](https://github.com/vburel2018) for creating Voicemeeter, its SDK, the C Remote API, the RT Packet service and Streamer View app!
[Vincent Burel](https://github.com/vburel2018) for creating Voicemeeter and its SDK.
[Rdbende](https://github.com/rdbende) for creating the beautiful Sun Valley Tkinter theme and adding it to Pypi!
[Rdbende](https://github.com/rdbende) for creating the beautiful [Sun Valley theme][sv-theme].
[sv-theme]: https://github.com/rdbende/Sun-Valley-ttk-theme

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 }

247
poetry.lock generated
View File

@@ -1,48 +1,71 @@
# 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.7.1 and should not be changed by hand.
[[package]]
name = "altgraph"
version = "0.17.4"
description = "Python graph (network) package"
optional = false
python-versions = "*"
files = [
{file = "altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff"},
{file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
]
[[package]]
name = "black"
version = "22.12.0"
version = "24.4.2"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
files = [
{file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"},
{file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"},
{file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"},
{file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"},
{file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"},
{file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"},
{file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"},
{file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"},
{file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"},
{file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"},
{file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"},
{file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"},
{file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
{file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
{file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
{file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
{file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
{file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
{file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
{file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
{file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
{file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
{file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
{file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
{file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
{file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
{file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
{file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
{file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
{file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
{file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
{file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
{file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
{file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
]
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
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]
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)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "click"
version = "8.1.4"
version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
{file = "click-8.1.4-py3-none-any.whl", hash = "sha256:2739815aaa5d2c986a88f1e9230c55e17f0caad3d958a5e13ad0797c166db9e3"},
{file = "click-8.1.4.tar.gz", hash = "sha256:b97d0c74955da062a7d4ef92fadb583806a585b2ea81958a81bd72726cbb8e37"},
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
@@ -61,20 +84,31 @@ files = [
[[package]]
name = "isort"
version = "5.12.0"
version = "5.13.2"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
{file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
]
[package.extras]
colors = ["colorama (>=0.4.3)"]
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
colors = ["colorama (>=0.4.6)"]
[[package]]
name = "macholib"
version = "1.16.3"
description = "Mach-O header analysis and editing"
optional = false
python-versions = "*"
files = [
{file = "macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c"},
{file = "macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30"},
]
[package.dependencies]
altgraph = ">=0.17"
[[package]]
name = "mypy-extensions"
@@ -87,41 +121,139 @@ files = [
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "24.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
[[package]]
name = "pathspec"
version = "0.11.1"
version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
files = [
{file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[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]]
name = "platformdirs"
version = "3.8.1"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
version = "4.2.2"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.7"
python-versions = ">=3.8"
files = [
{file = "platformdirs-3.8.1-py3-none-any.whl", hash = "sha256:cec7b889196b9144d088e4c57d9ceef7374f6c39694ad1577a0aab50d27ea28c"},
{file = "platformdirs-3.8.1.tar.gz", hash = "sha256:f87ca4fcff7d2b0f81c6a748a77973d7af0f4d526f98f308477c3c436c74d528"},
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
]
[package.extras]
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)"]
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
type = ["mypy (>=1.8)"]
[[package]]
name = "sv-ttk"
version = "2.5.3"
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
name = "pyinstaller"
version = "6.8.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.8.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ff6bc2784c1026f8e2f04aa3760cbed41408e108a9d4cf1dd52ee8351a3f6e1"},
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:39ac424d2ee2457d2ab11a5091436e75a0cccae207d460d180aa1fcbbafdd528"},
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_i686.whl", hash = "sha256:355832a3acc7de90a255ecacd4b9f9e166a547a79c8905d49f14e3a75c1acdb9"},
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:6303c7a009f47e6a96ef65aed49f41e36ece8d079b9193ca92fe807403e5fe80"},
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2b71509468c811968c0b5decb5bbe85b6292ea52d7b1f26313d2aabb673fa9a5"},
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ff31c5b99e05a4384bbe2071df67ec8b2b347640a375eae9b40218be2f1754c6"},
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:000c36b13fe4cd8d0d8c2bc855b1ddcf39867b5adf389e6b5ca45b25fa3e619d"},
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:fe0af018d7d5077180e3144ada89a4da5df8d07716eb7e9482834a56dc57a4e8"},
{file = "pyinstaller-6.8.0-py3-none-win32.whl", hash = "sha256:d257f6645c7334cbd66f38a4fac62c3ad614cc46302b2b5d9f8cc48c563bce0e"},
{file = "pyinstaller-6.8.0-py3-none-win_amd64.whl", hash = "sha256:81cccfa9b16699b457f4788c5cc119b50f3cd4d0db924955f15c33f2ad27a50d"},
{file = "pyinstaller-6.8.0-py3-none-win_arm64.whl", hash = "sha256:1c3060a263758cf7f0144ab4c016097b20451b2469d468763414665db1bb743d"},
{file = "pyinstaller-6.8.0.tar.gz", hash = "sha256:3f4b6520f4423fe19bcc2fd63ab7238851ae2bdcbc98f25bc5d2f97cc62012e9"},
]
[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 = ">=2024.6"
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 = "2024.7"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.7"
files = [
{file = "sv_ttk-2.5.3-py3-none-any.whl", hash = "sha256:d13bf6a7b49316431eefcf83f30d0daf312c00553c4e0b6f91acffd7b2aaa1d3"},
{file = "sv_ttk-2.5.3.tar.gz", hash = "sha256:d9b9a5d14f4cbdd4e0bda2e1a84445b0aa852b99f74aafce9386459e385717b3"},
{file = "pyinstaller_hooks_contrib-2024.7-py2.py3-none-any.whl", hash = "sha256:8bf0775771fbaf96bcd2f4dfd6f7ae6c1dd1b1efe254c7e50477b3c08e7841d8"},
{file = "pyinstaller_hooks_contrib-2024.7.tar.gz", hash = "sha256:fd5f37dcf99bece184e40642af88be16a9b89613ecb958a8bd1136634fc9fac5"},
]
[package.dependencies]
packaging = ">=22.0"
setuptools = ">=42.0.0"
[[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 = "70.2.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
{file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
]
[package.extras]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "sv-ttk"
version = "2.6.0"
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
optional = false
python-versions = ">=3.8"
files = [
{file = "sv_ttk-2.6.0-py3-none-any.whl", hash = "sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"},
{file = "sv_ttk-2.6.0.tar.gz", hash = "sha256:3fd440396c95e30e88f686fcf28be425480f7320d6bf346f9cea5d6f56702cc2"},
]
[[package]]
@@ -135,15 +267,26 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
]
[[package]]
name = "vban-cmd"
version = "2.3.2"
version = "2.4.11"
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
optional = false
python-versions = ">=3.10,<4.0"
files = [
{file = "vban_cmd-2.3.2-py3-none-any.whl", hash = "sha256:28168a7ec1c6966fd4bcbaed3144219f8cdc2490f15dd8ecba2aa19f2a3461f5"},
{file = "vban_cmd-2.3.2.tar.gz", hash = "sha256:c33e338e3207f35a6b9f9026d29cf68af9e5f6d7c96aea4b581225f4befd844e"},
{file = "vban_cmd-2.4.11-py3-none-any.whl", hash = "sha256:a74b7631222f340488f5d45bc9aa9d4e7a0f919687c9715619e8809c684875b7"},
{file = "vban_cmd-2.4.11.tar.gz", hash = "sha256:250ca8043f075eee11d2a811142d0205900d14d7e2f0cd98eb597901ead738f5"},
]
[package.dependencies]
@@ -151,13 +294,13 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[[package]]
name = "voicemeeter-api"
version = "2.3.2"
version = "2.6.0"
description = "A Python wrapper for the Voiceemeter API"
optional = false
python-versions = ">=3.10,<4.0"
python-versions = "<4.0,>=3.10"
files = [
{file = "voicemeeter_api-2.3.2-py3-none-any.whl", hash = "sha256:081bd6b3e27d8757e4c5ed239b4c58f9bcb4f4d16ebc9c88229e9390dac184c8"},
{file = "voicemeeter_api-2.3.2.tar.gz", hash = "sha256:aa700600b5910e4bb55df20cdf028aae2a44cc14bfd80dd0fe060aa03bbf7e02"},
{file = "voicemeeter_api-2.6.0-py3-none-any.whl", hash = "sha256:c2ef8eb063ce3aeac4827ad7883150c407a0effb0fde3778782cd3024a295255"},
{file = "voicemeeter_api-2.6.0.tar.gz", hash = "sha256:db93f27b58ce927c7d56084b224e1d0cdd6406ab7f26e4f99a9a873495a3d2e7"},
]
[package.dependencies]
@@ -165,5 +308,5 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "770291c3645dd9bfd28051c0deb13bf5ae17a510bfc2785b51be1bc5c7266b1a"
python-versions = ">=3.10,<3.13"
content-hash = "343eb64c79bba2d92eeb9af614c782dd175bd8a7b1a236a330b1dd9ae4d18a57"

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "voicemeeter-compact"
version = "1.9.1"
version = "1.9.5"
description = "A Compact Voicemeeter Remote App"
authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT"
@@ -11,16 +11,25 @@ packages = [{ include = "vmcompact" }]
include = ["vmcompact/img/cat.ico"]
[tool.poetry.dependencies]
python = "^3.10"
sv-ttk = "^2.5.1"
python = ">=3.10,<3.13"
sv-ttk = "^2.6.0"
tomli = { version = "^2.0.1", python = "<3.11" }
voicemeeter-api = "^2.3.2"
vban-cmd = "^2.3.2"
voicemeeter-api = "^2.6.0"
vban-cmd = "^2.4.11"
[tool.poetry.dev-dependencies]
black = { version = "^22.6.0", allow-prereleases = true }
[tool.poetry.group.dev.dependencies]
black = { version = ">=22.6,<25.0", allow-prereleases = true }
isort = "^5.12.0"
[tool.poetry.group.build.dependencies]
pyinstaller = "^6.3.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
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._vmr = vmr
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()
icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico"
if icon_path.is_file():
self.iconbitmap(str(icon_path))
self.minsize(275, False)
self.subject = Subject()
self._configs = None
self.protocol("WM_DELETE_WINDOW", self.on_close_window)
self.menu = self["menu"] = Menus(self, vmr)
self.styletable = ttk.Style()
if _configuration.config:
@@ -147,10 +148,15 @@ class App(tk.Tk):
return self._configs
def start_updates(self):
self.logger.debug("updates started")
_base_values.run_update = True
def init():
self.logger.debug("updates started")
_base_values.run_update = True
if self._vmr.gui.launched_by_api:
self.on_pdirty()
self.subject.notify("pdirty")
self.after(12000, init)
else:
init()
def healthcheck_step(self):
if not _base_values.vban_connected:
@@ -182,6 +188,11 @@ class App(tk.Tk):
self.destroy()
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}

View File

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

View File

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