Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 45a1f34c00 | |||
| 6256ba597e | |||
| 47b452fe5f | |||
| 5d7599891c | |||
| eb9d4c8cf9 | |||
| 123a2126ee |
@@ -1,46 +0,0 @@
|
|||||||
name: PyInstaller Build
|
|
||||||
on: [push]
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Python
|
|
||||||
uses: actions/setup-python@v4
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
|
|
||||||
- name: Install system dependencies for wxPython
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y \
|
|
||||||
libgtk-3-dev \
|
|
||||||
libnotify-dev \
|
|
||||||
libsdl2-dev \
|
|
||||||
libsm-dev \
|
|
||||||
libwebkit2gtk-4.1-dev \
|
|
||||||
libgstreamer1.0-dev \
|
|
||||||
libgstreamer-plugins-base1.0-dev \
|
|
||||||
freeglut3-dev \
|
|
||||||
libgstreamer-plugins-bad1.0-dev \
|
|
||||||
libpng-dev \
|
|
||||||
libjpeg-dev \
|
|
||||||
libtiff-dev
|
|
||||||
|
|
||||||
- name: Install Python dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip setuptools wheel
|
|
||||||
pip install -r requirements.txt
|
|
||||||
pip install wxPython
|
|
||||||
pip install pyinstaller
|
|
||||||
|
|
||||||
- name: Build with PyInstaller
|
|
||||||
run: pyinstaller --onefile --name myapp main.py
|
|
||||||
|
|
||||||
- name: Upload Executable
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: myapp-linux
|
|
||||||
path: dist/myapp
|
|
||||||
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Build artifacts
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Python cache
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# OS / editor
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
*.lock
|
||||||
13
Pipfile
Normal file
13
Pipfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
wxpython = ">=4.2.1"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.13"
|
||||||
|
python_full_version = "3.13.0"
|
||||||
54
Pipfile.lock
generated
Normal file
54
Pipfile.lock
generated
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "aa9b33f7d109f733590656072ed7ed1c726327a41dccf82b9f333300f25e468c"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_full_version": "3.13.0",
|
||||||
|
"python_version": "3.13"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"wxpython": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0985f190565b94635f146989886196a7e9faced8911800910460919cb72668cc",
|
||||||
|
"sha256:10bba0d56547f34d12b5450e8c73e32ff821aed10a2f34a0c666c8355eb9ee98",
|
||||||
|
"sha256:1925485c9b90e79f869272eff2b99438538b00505f9d148d51358dc8e92116b6",
|
||||||
|
"sha256:230ecb4de65a8d2f8bc30bccd4d64366ac3a7cf53759b77920de927d156ad9c5",
|
||||||
|
"sha256:26f80c81a150c90c14b50cbb246b7048d65d737d0206d28a6860171b273af932",
|
||||||
|
"sha256:310772b05372c2daa76fefa7e57d20106b522d53b49d3edc3d9ac1fde7e3782e",
|
||||||
|
"sha256:3fd3649fc4752f1a02776b7057073c932e5229bbab2031762b01532bcc6bd074",
|
||||||
|
"sha256:402c61ea6c9f2904b0e0c2ffbd04ed38ad6ae4f25e0d9de529dbf44da0685346",
|
||||||
|
"sha256:44e836d1bccd99c38790bb034b6ecf70d9060f6734320560f7c4b0d006144793",
|
||||||
|
"sha256:508de82ac2b64aa575a543949c44dc7f83a734622bed01d8501474ab454f7bb7",
|
||||||
|
"sha256:5f7ec6b028e8b1c4cad1ecb5c8402c2cae7840a25758be0fc209e56df86d1cac",
|
||||||
|
"sha256:74fc76f8d22226e607d7072278cc09052da0cda508dea14a9933b014a4e5aeeb",
|
||||||
|
"sha256:77ac5335d8e4aae92732fc039df24a58181cdfb5bc7931692f1f9415e9eeee7d",
|
||||||
|
"sha256:9bf5704eedd21bd1fe3143d8ed1cfe8250e1fbb651eb6c17a73533136745fe5a",
|
||||||
|
"sha256:a5ecb93cc17e09e90d71a1f8d99a543268a5f019aeec058b24374926f79bb6fc",
|
||||||
|
"sha256:ade4d6b39c39770146ce1010df7d7a5a767d148b478133d49c36dffb0880a174",
|
||||||
|
"sha256:af2d8388eb3f0d8eaae0713a35c307293435ec279f215a2bbf521b738d7fc91b",
|
||||||
|
"sha256:b794d9912464990ea1fd3744fb73fbd7446149e230e5a611ba40eb4ac74755a1",
|
||||||
|
"sha256:c54962f0524662d16591a03c786cd4d71bc43c70ede8244e0a5a59aa3979d124",
|
||||||
|
"sha256:c97ccd3f2da567eff43f71948d9ace86c91dc80aa834e7b2dbeacd95eabbe9c6",
|
||||||
|
"sha256:cda1fb351caa4555bd18717f610c9a3b03d25e64db4a22e004b141f91d02fa8c",
|
||||||
|
"sha256:d4439bf4b18ac720afbcf51c37d7822ba62ab6999501e96cce1dfc2f55a19344",
|
||||||
|
"sha256:d7e3b69a1f2ad383e8305efee11130dbe7542b6f6d8d5ba02fdce3cfc4c67ad6",
|
||||||
|
"sha256:e7079d9a7374b3fd5896bdea7c73faa8da52e1fbcce5368796b5c22d7de747a6",
|
||||||
|
"sha256:eb1c228f0c20ed93f2799ebd81780abc7fd65cfa8f6b65e989b68c0c18c52707"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"markers": "python_version >= '3.10'",
|
||||||
|
"version": "==4.2.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -380,18 +380,6 @@
|
|||||||
('pathlib._abc',
|
('pathlib._abc',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('json',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.encoder',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\encoder.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.decoder',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\decoder.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('json.scanner',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\scanner.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('__future__',
|
('__future__',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -503,8 +491,8 @@
|
|||||||
('multiprocessing',
|
('multiprocessing',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\multiprocessing\\__init__.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\multiprocessing\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('_py_abc',
|
('stringprep',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('tracemalloc',
|
('tracemalloc',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
|
||||||
@@ -512,8 +500,11 @@
|
|||||||
('_colorize',
|
('_colorize',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('stringprep',
|
('_py_abc',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('wx.media',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\media.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('wx',
|
('wx',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\__init__.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\__init__.py',
|
||||||
@@ -667,6 +658,18 @@
|
|||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('_threading_local',
|
('_threading_local',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_threading_local.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_threading_local.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\__init__.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.encoder',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\encoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.decoder',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\decoder.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('json.scanner',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\scanner.py',
|
||||||
'PYMODULE')],
|
'PYMODULE')],
|
||||||
[('python313.dll',
|
[('python313.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
||||||
@@ -707,6 +710,9 @@
|
|||||||
('_queue.pyd',
|
('_queue.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
|
('wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
('_overlapped.pyd',
|
('_overlapped.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
@@ -731,12 +737,12 @@
|
|||||||
('VCRUNTIME140.dll',
|
('VCRUNTIME140.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
('libcrypto-3.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('libssl-3.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
||||||
|
'BINARY'),
|
||||||
('libffi-8.dll',
|
('libffi-8.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
@@ -749,6 +755,9 @@
|
|||||||
('wx\\wxbase32u_vc140_x64.dll',
|
('wx\\wxbase32u_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'BINARY'),
|
||||||
('wx\\wxmsw32u_html_vc140_x64.dll',
|
('wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
@@ -759,48 +768,15 @@
|
|||||||
[],
|
[],
|
||||||
[],
|
[],
|
||||||
[('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
|
[('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
|
||||||
[('_collections_abc',
|
[('io',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_collections_abc.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\io.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('_weakrefset',
|
('operator',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\operator.py',
|
||||||
'PYMODULE'),
|
|
||||||
('abc',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_constants',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_constants.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('collections.abc',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\abc.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('collections',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\__init__.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_compile',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_compile.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('warnings',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\warnings.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('traceback',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\traceback.py',
|
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('types',
|
('types',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\types.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\types.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('io',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\io.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('enum',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\enum.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('sre_parse',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_parse.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('weakref',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\weakref.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('encodings.zlib_codec',
|
('encodings.zlib_codec',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\zlib_codec.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\zlib_codec.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -1167,24 +1143,51 @@
|
|||||||
('encodings',
|
('encodings',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\__init__.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('linecache',
|
('sre_constants',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\linecache.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_constants.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('codecs',
|
('collections.abc',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\codecs.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\abc.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('genericpath',
|
('collections',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\genericpath.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\__init__.py',
|
||||||
'PYMODULE'),
|
|
||||||
('copyreg',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copyreg.py',
|
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('keyword',
|
('keyword',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('genericpath',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\genericpath.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('enum',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\enum.py',
|
||||||
|
'PYMODULE'),
|
||||||
('reprlib',
|
('reprlib',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\reprlib.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\reprlib.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('_collections_abc',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_collections_abc.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('warnings',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\warnings.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('linecache',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\linecache.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('posixpath',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\posixpath.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('functools',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\functools.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('codecs',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\codecs.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('copyreg',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copyreg.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('traceback',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\traceback.py',
|
||||||
|
'PYMODULE'),
|
||||||
('re._parser',
|
('re._parser',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\_parser.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\_parser.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
@@ -1200,26 +1203,32 @@
|
|||||||
('re',
|
('re',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\__init__.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\__init__.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('heapq',
|
('_weakrefset',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\heapq.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('functools',
|
('abc',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\functools.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py',
|
||||||
'PYMODULE'),
|
|
||||||
('operator',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\operator.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('ntpath',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ntpath.py',
|
|
||||||
'PYMODULE'),
|
|
||||||
('stat',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stat.py',
|
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('locale',
|
('locale',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\locale.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\locale.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('posixpath',
|
('weakref',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\posixpath.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\weakref.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('stat',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stat.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('ntpath',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ntpath.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('sre_parse',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_parse.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('sre_compile',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_compile.py',
|
||||||
|
'PYMODULE'),
|
||||||
|
('heapq',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\heapq.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
('os',
|
('os',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\os.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\os.py',
|
||||||
|
|||||||
@@ -97,6 +97,9 @@
|
|||||||
('_queue.pyd',
|
('_queue.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
|
('wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
('_overlapped.pyd',
|
('_overlapped.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
@@ -121,12 +124,12 @@
|
|||||||
('VCRUNTIME140.dll',
|
('VCRUNTIME140.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
('libcrypto-3.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('libssl-3.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
||||||
|
'BINARY'),
|
||||||
('libffi-8.dll',
|
('libffi-8.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
@@ -139,6 +142,9 @@
|
|||||||
('wx\\wxbase32u_vc140_x64.dll',
|
('wx\\wxbase32u_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'BINARY'),
|
||||||
('wx\\wxmsw32u_html_vc140_x64.dll',
|
('wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
@@ -150,7 +156,7 @@
|
|||||||
[],
|
[],
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
1770822014,
|
1770922631,
|
||||||
[('run.exe',
|
[('run.exe',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||||
'EXECUTABLE')],
|
'EXECUTABLE')],
|
||||||
|
|||||||
@@ -75,6 +75,9 @@
|
|||||||
('_queue.pyd',
|
('_queue.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
|
('wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\_media.cp313-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
('_overlapped.pyd',
|
('_overlapped.pyd',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
||||||
'EXTENSION'),
|
'EXTENSION'),
|
||||||
@@ -99,12 +102,12 @@
|
|||||||
('VCRUNTIME140.dll',
|
('VCRUNTIME140.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
('libssl-3.dll',
|
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
|
||||||
'BINARY'),
|
|
||||||
('libcrypto-3.dll',
|
('libcrypto-3.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('libssl-3.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
||||||
|
'BINARY'),
|
||||||
('libffi-8.dll',
|
('libffi-8.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
@@ -117,6 +120,9 @@
|
|||||||
('wx\\wxbase32u_vc140_x64.dll',
|
('wx\\wxbase32u_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
('wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_media_vc140_x64.dll',
|
||||||
|
'BINARY'),
|
||||||
('wx\\wxmsw32u_html_vc140_x64.dll',
|
('wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
|
||||||
'BINARY'),
|
'BINARY'),
|
||||||
|
|||||||
Binary file not shown.
@@ -587,6 +587,9 @@
|
|||||||
('wx.lib.colourutils',
|
('wx.lib.colourutils',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\lib\\colourutils.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\lib\\colourutils.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
('wx.media',
|
||||||
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\media.py',
|
||||||
|
'PYMODULE'),
|
||||||
('wx.msw',
|
('wx.msw',
|
||||||
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\msw.py',
|
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\msw.py',
|
||||||
'PYMODULE'),
|
'PYMODULE'),
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -17,12 +17,12 @@ IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
|||||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||||
missing module named _scproxy - imported by urllib.request (conditional)
|
missing module named _scproxy - imported by urllib.request (conditional)
|
||||||
missing module named termios - imported by getpass (optional)
|
missing module named termios - imported by getpass (optional)
|
||||||
missing module named pwd - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), posixpath (delayed, conditional, optional), netrc (delayed, conditional), getpass (delayed, optional)
|
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), netrc (delayed, conditional), getpass (delayed, optional)
|
||||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||||
missing module named posix - imported by shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional), posixpath (optional)
|
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
|
||||||
missing module named resource - imported by posix (top-level)
|
missing module named resource - imported by posix (top-level)
|
||||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ imports:
|
|||||||
• <a href="#genericpath">genericpath</a>
|
• <a href="#genericpath">genericpath</a>
|
||||||
• <a href="#heapq">heapq</a>
|
• <a href="#heapq">heapq</a>
|
||||||
• <a href="#io">io</a>
|
• <a href="#io">io</a>
|
||||||
|
• <a href="#json">json</a>
|
||||||
• <a href="#keyword">keyword</a>
|
• <a href="#keyword">keyword</a>
|
||||||
• <a href="#linecache">linecache</a>
|
• <a href="#linecache">linecache</a>
|
||||||
• <a href="#locale">locale</a>
|
• <a href="#locale">locale</a>
|
||||||
@@ -180,6 +181,7 @@ imports:
|
|||||||
• <a href="#warnings">warnings</a>
|
• <a href="#warnings">warnings</a>
|
||||||
• <a href="#weakref">weakref</a>
|
• <a href="#weakref">weakref</a>
|
||||||
• <a href="#wx">wx</a>
|
• <a href="#wx">wx</a>
|
||||||
|
• <a href="#wx.media">wx.media</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -7205,6 +7207,7 @@ imported by:
|
|||||||
• <a href="#json.decoder">json.decoder</a>
|
• <a href="#json.decoder">json.decoder</a>
|
||||||
• <a href="#json.encoder">json.encoder</a>
|
• <a href="#json.encoder">json.encoder</a>
|
||||||
• <a href="#json.scanner">json.scanner</a>
|
• <a href="#json.scanner">json.scanner</a>
|
||||||
|
• <a href="#main.py">main.py</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -10346,12 +10349,14 @@ imported by:
|
|||||||
• <a href="#wx._adv">wx._adv</a>
|
• <a href="#wx._adv">wx._adv</a>
|
||||||
• <a href="#wx._core">wx._core</a>
|
• <a href="#wx._core">wx._core</a>
|
||||||
• <a href="#wx._html">wx._html</a>
|
• <a href="#wx._html">wx._html</a>
|
||||||
|
• <a href="#wx._media">wx._media</a>
|
||||||
• <a href="#wx._msw">wx._msw</a>
|
• <a href="#wx._msw">wx._msw</a>
|
||||||
• <a href="#wx.adv">wx.adv</a>
|
• <a href="#wx.adv">wx.adv</a>
|
||||||
• <a href="#wx.core">wx.core</a>
|
• <a href="#wx.core">wx.core</a>
|
||||||
• <a href="#wx.html">wx.html</a>
|
• <a href="#wx.html">wx.html</a>
|
||||||
• <a href="#wx.lib">wx.lib</a>
|
• <a href="#wx.lib">wx.lib</a>
|
||||||
• <a href="#wx.lib.colourutils">wx.lib.colourutils</a>
|
• <a href="#wx.lib.colourutils">wx.lib.colourutils</a>
|
||||||
|
• <a href="#wx.media">wx.media</a>
|
||||||
• <a href="#wx.msw">wx.msw</a>
|
• <a href="#wx.msw">wx.msw</a>
|
||||||
• <a href="#wx.siplib">wx.siplib</a>
|
• <a href="#wx.siplib">wx.siplib</a>
|
||||||
|
|
||||||
@@ -10421,6 +10426,21 @@ imported by:
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="node">
|
||||||
|
<a name="wx._media"></a>
|
||||||
|
<tt>wx._media</tt> <span class="moduletype"><tt>C:\Users\aaron\AppData\Local\Programs\Python\Python313\Lib\site-packages\wx\_media.cp313-win_amd64.pyd</tt></span> <div class="import">
|
||||||
|
imports:
|
||||||
|
<a href="#wx">wx</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="import">
|
||||||
|
imported by:
|
||||||
|
<a href="#wx.media">wx.media</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="wx._msw"></a>
|
<a name="wx._msw"></a>
|
||||||
<tt>wx._msw</tt> <span class="moduletype"><tt>C:\Users\aaron\AppData\Local\Programs\Python\Python313\Lib\site-packages\wx\_msw.cp313-win_amd64.pyd</tt></span> <div class="import">
|
<tt>wx._msw</tt> <span class="moduletype"><tt>C:\Users\aaron\AppData\Local\Programs\Python\Python313\Lib\site-packages\wx\_msw.cp313-win_amd64.pyd</tt></span> <div class="import">
|
||||||
@@ -10538,6 +10558,23 @@ imported by:
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="node">
|
||||||
|
<a name="wx.media"></a>
|
||||||
|
<a target="code" href="///C:/Users/aaron/AppData/Local/Programs/Python/Python313/Lib/site-packages/wx/media.py" type="text/plain"><tt>wx.media</tt></a>
|
||||||
|
<span class="moduletype">SourceModule</span> <div class="import">
|
||||||
|
imports:
|
||||||
|
<a href="#wx">wx</a>
|
||||||
|
• <a href="#wx._media">wx._media</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="import">
|
||||||
|
imported by:
|
||||||
|
<a href="#main.py">main.py</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="node">
|
<div class="node">
|
||||||
<a name="wx.msw"></a>
|
<a name="wx.msw"></a>
|
||||||
<a target="code" href="///C:/Users/aaron/AppData/Local/Programs/Python/Python313/Lib/site-packages/wx/msw.py" type="text/plain"><tt>wx.msw</tt></a>
|
<a target="code" href="///C:/Users/aaron/AppData/Local/Programs/Python/Python313/Lib/site-packages/wx/msw.py" type="text/plain"><tt>wx.msw</tt></a>
|
||||||
|
|||||||
BIN
dist/main.exe
vendored
BIN
dist/main.exe
vendored
Binary file not shown.
364
main.py
364
main.py
@@ -1,20 +1,26 @@
|
|||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import threading
|
import threading
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import wx
|
import wx
|
||||||
import wx.media
|
import wx.media
|
||||||
|
|
||||||
AUDIO_FORMATS = ["mp3", "wav", "aac", "flac", "ogg", "m4a"]
|
AUDIO_FORMATS = ["mp3", "wav", "aac", "flac", "ogg", "m4a", "m4b"]
|
||||||
VIDEO_FORMATS = ["mp4", "mkv", "mov", "webm"]
|
VIDEO_FORMATS = ["mp4", "mkv", "mov", "webm"]
|
||||||
|
|
||||||
|
|
||||||
class ConverterFrame(wx.Frame):
|
class ConverterFrame(wx.Frame):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(parent=None, title="Audio/Video Converter", size=(720, 460))
|
super().__init__(parent=None, title="Audio/Video Converter", size=(640, 380))
|
||||||
panel = wx.Panel(self)
|
panel = wx.Panel(self)
|
||||||
|
label_color = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)
|
||||||
|
|
||||||
self.input_picker = wx.FilePickerCtrl(panel, message="Select input file")
|
self.input_picker = wx.FilePickerCtrl(
|
||||||
|
panel,
|
||||||
|
message="Select input file",
|
||||||
|
style=wx.FLP_OPEN | wx.FLP_FILE_MUST_EXIST | wx.FLP_USE_TEXTCTRL,
|
||||||
|
)
|
||||||
self.mode_choice = wx.Choice(panel, choices=["Audio", "Video"])
|
self.mode_choice = wx.Choice(panel, choices=["Audio", "Video"])
|
||||||
self.mode_choice.SetSelection(0)
|
self.mode_choice.SetSelection(0)
|
||||||
self.format_choice = wx.Choice(panel, choices=AUDIO_FORMATS)
|
self.format_choice = wx.Choice(panel, choices=AUDIO_FORMATS)
|
||||||
@@ -22,24 +28,30 @@ class ConverterFrame(wx.Frame):
|
|||||||
self.output_picker = wx.FilePickerCtrl(
|
self.output_picker = wx.FilePickerCtrl(
|
||||||
panel,
|
panel,
|
||||||
message="Select output file",
|
message="Select output file",
|
||||||
style=wx.FLP_SAVE | wx.FLP_OVERWRITE_PROMPT,
|
style=wx.FLP_SAVE | wx.FLP_OVERWRITE_PROMPT | wx.FLP_USE_TEXTCTRL,
|
||||||
)
|
)
|
||||||
self.audio_bitrate = wx.TextCtrl(panel, value="", size=(120, -1))
|
self.audio_bitrate = wx.TextCtrl(panel, value="", size=(120, -1))
|
||||||
self.video_bitrate = wx.TextCtrl(panel, value="", size=(120, -1))
|
self.video_bitrate = wx.TextCtrl(panel, value="", size=(120, -1))
|
||||||
self.copy_streams = wx.CheckBox(panel, label="Copy streams (fast, no re-encode)")
|
self.activation_bytes = wx.TextCtrl(panel, value="", size=(120, -1))
|
||||||
self.start_btn = wx.Button(panel, label="Convert")
|
self.copy_streams = wx.CheckBox(panel, label="Co&py streams (fast, no re-encode)")
|
||||||
|
self.copy_streams.SetForegroundColour(label_color)
|
||||||
|
self.split_mp3_choice = wx.Choice(panel, choices=["No", "Yes"])
|
||||||
|
self.split_mp3_choice.SetSelection(0)
|
||||||
|
self.start_btn = wx.Button(panel, label="&Convert")
|
||||||
self.log_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY)
|
self.log_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY)
|
||||||
self.status = wx.StaticText(panel, label="Ready")
|
self.status = wx.StaticText(panel, label="Ready")
|
||||||
|
self.status.SetForegroundColour(label_color)
|
||||||
|
self.progress_gauge = wx.Gauge(panel, range=1000, style=wx.GA_HORIZONTAL)
|
||||||
|
self.progress_gauge.SetValue(0)
|
||||||
|
self.progress_label = wx.StaticText(panel, label="Progress")
|
||||||
|
self.progress_label.SetForegroundColour(label_color)
|
||||||
|
|
||||||
self.media = wx.media.MediaCtrl(panel, style=wx.SIMPLE_BORDER)
|
self.media = wx.media.MediaCtrl(panel, style=wx.SIMPLE_BORDER)
|
||||||
self.play_btn = wx.Button(panel, label="Play/Pause")
|
self.play_btn = wx.Button(panel, label="&Play/Pause")
|
||||||
self.stop_btn = wx.Button(panel, label="Stop")
|
self.stop_btn = wx.Button(panel, label="S&top")
|
||||||
self.position_slider = wx.Slider(panel, minValue=0, maxValue=1000, style=wx.SL_HORIZONTAL)
|
self.position_slider = wx.Slider(panel, minValue=0, maxValue=1000, style=wx.SL_HORIZONTAL)
|
||||||
self.time_label = wx.StaticText(panel, label="00:00 / 00:00")
|
self.time_label = wx.StaticText(panel, label="00:00 / 00:00")
|
||||||
self.hotkeys_label = wx.StaticText(
|
self.time_label.SetForegroundColour(label_color)
|
||||||
panel,
|
|
||||||
label="Hotkeys: Space Play/Pause, Ctrl+S Stop, Ctrl+Enter Convert, Alt+Left/Right Seek",
|
|
||||||
)
|
|
||||||
self.media_length_ms = 0
|
self.media_length_ms = 0
|
||||||
self.dragging_slider = False
|
self.dragging_slider = False
|
||||||
self.pending_play = False
|
self.pending_play = False
|
||||||
@@ -49,47 +61,54 @@ class ConverterFrame(wx.Frame):
|
|||||||
|
|
||||||
self.audio_bitrate.SetHint("e.g. 192k")
|
self.audio_bitrate.SetHint("e.g. 192k")
|
||||||
self.video_bitrate.SetHint("e.g. 2000k")
|
self.video_bitrate.SetHint("e.g. 2000k")
|
||||||
|
self.activation_bytes.SetHint("e.g. 1")
|
||||||
|
self.audio_bitrate.SetName("Audio bitrate")
|
||||||
|
self.video_bitrate.SetName("Video bitrate")
|
||||||
|
self.activation_bytes.SetName("Activation bytes")
|
||||||
|
self.configure_file_picker_accessibility(self.input_picker, "Input file")
|
||||||
|
self.mode_choice.SetName("Conversion mode")
|
||||||
|
self.format_choice.SetName("Output format")
|
||||||
|
self.configure_file_picker_accessibility(self.output_picker, "Output file")
|
||||||
|
self.copy_streams.SetName("Copy streams")
|
||||||
|
self.split_mp3_choice.SetName("Split MP3 into captures")
|
||||||
|
self.start_btn.SetName("Convert")
|
||||||
|
self.play_btn.SetName("Play or pause")
|
||||||
|
self.stop_btn.SetName("Stop playback")
|
||||||
|
self.input_picker.SetHelpText("Input file")
|
||||||
|
self.mode_choice.SetHelpText("Conversion mode")
|
||||||
|
self.format_choice.SetHelpText("Output format")
|
||||||
|
self.output_picker.SetHelpText("Output file")
|
||||||
|
self.audio_bitrate.SetHelpText("Audio bitrate")
|
||||||
|
self.video_bitrate.SetHelpText("Video bitrate")
|
||||||
|
self.activation_bytes.SetHelpText("Activation bytes")
|
||||||
|
self.copy_streams.SetHelpText("Copy streams")
|
||||||
|
self.split_mp3_choice.SetHelpText("Split MP3 output into captures based on chapters")
|
||||||
|
self.start_btn.SetHelpText("Convert")
|
||||||
|
self.play_btn.SetHelpText("Play or pause")
|
||||||
|
self.stop_btn.SetHelpText("Stop playback")
|
||||||
self.media.SetMinSize((200, 36))
|
self.media.SetMinSize((200, 36))
|
||||||
if hasattr(self.media, "SetVolume"):
|
if hasattr(self.media, "SetVolume"):
|
||||||
self.media.SetVolume(1.0)
|
self.media.SetVolume(1.0)
|
||||||
|
|
||||||
form = wx.FlexGridSizer(cols=3, hgap=8, vgap=8)
|
form = wx.BoxSizer(wx.VERTICAL)
|
||||||
form.Add(wx.StaticText(panel, label="Input"), 0, wx.ALIGN_CENTER_VERTICAL)
|
self.add_labeled_control(panel, form, "&Input file", self.input_picker, "Input file")
|
||||||
form.Add(self.input_picker, 1, wx.EXPAND)
|
self.add_labeled_control(panel, form, "&Mode", self.mode_choice, "Conversion mode")
|
||||||
form.Add((1, 1))
|
self.add_labeled_control(panel, form, "F&ormat", self.format_choice, "Output format")
|
||||||
|
self.add_labeled_control(panel, form, "O&utput file", self.output_picker, "Output file")
|
||||||
form.Add(wx.StaticText(panel, label="Mode"), 0, wx.ALIGN_CENTER_VERTICAL)
|
self.add_labeled_control(panel, form, "Audio &bitrate", self.audio_bitrate, "Audio bitrate")
|
||||||
form.Add(self.mode_choice, 0)
|
self.add_labeled_control(panel, form, "Video b&itrate", self.video_bitrate, "Video bitrate")
|
||||||
form.Add((1, 1))
|
self.add_labeled_control(panel, form, "A&ctivation bytes", self.activation_bytes, "Activation bytes")
|
||||||
|
form.Add(self.copy_streams, 0, wx.EXPAND | wx.BOTTOM, 6)
|
||||||
form.Add(wx.StaticText(panel, label="Format"), 0, wx.ALIGN_CENTER_VERTICAL)
|
self.add_labeled_control(panel, form, "Split MP3 into &captures", self.split_mp3_choice, "Split MP3 into captures")
|
||||||
form.Add(self.format_choice, 0)
|
|
||||||
form.Add((1, 1))
|
|
||||||
|
|
||||||
form.Add(wx.StaticText(panel, label="Output"), 0, wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
form.Add(self.output_picker, 1, wx.EXPAND)
|
|
||||||
form.Add((1, 1))
|
|
||||||
|
|
||||||
form.Add(wx.StaticText(panel, label="Audio bitrate"), 0, wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
form.Add(self.audio_bitrate, 0)
|
|
||||||
form.Add(wx.StaticText(panel, label="Optional"), 0, wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
|
|
||||||
form.Add(wx.StaticText(panel, label="Video bitrate"), 0, wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
form.Add(self.video_bitrate, 0)
|
|
||||||
form.Add(wx.StaticText(panel, label="Optional"), 0, wx.ALIGN_CENTER_VERTICAL)
|
|
||||||
|
|
||||||
form.Add(wx.StaticText(panel, label=""), 0)
|
|
||||||
form.Add(self.copy_streams, 0)
|
|
||||||
form.Add((1, 1))
|
|
||||||
|
|
||||||
form.AddGrowableCol(1, 1)
|
|
||||||
|
|
||||||
main = wx.BoxSizer(wx.VERTICAL)
|
main = wx.BoxSizer(wx.VERTICAL)
|
||||||
main.Add(form, 0, wx.EXPAND | wx.ALL, 12)
|
main.Add(form, 0, wx.EXPAND | wx.ALL, 10)
|
||||||
main.Add(self.start_btn, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 12)
|
main.Add(self.start_btn, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
|
||||||
main.Add(self.build_player(panel), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 12)
|
main.Add(self.build_player(panel), 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
|
||||||
main.Add(self.log_ctrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 12)
|
main.Add(self.progress_label, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)
|
||||||
main.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 12)
|
main.Add(self.progress_gauge, 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
|
||||||
|
main.Add(self.log_ctrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
|
||||||
|
main.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
|
||||||
|
|
||||||
panel.SetSizer(main)
|
panel.SetSizer(main)
|
||||||
|
|
||||||
@@ -131,6 +150,7 @@ class ConverterFrame(wx.Frame):
|
|||||||
choices = VIDEO_FORMATS
|
choices = VIDEO_FORMATS
|
||||||
self.format_choice.Set(choices)
|
self.format_choice.Set(choices)
|
||||||
self.format_choice.SetSelection(0)
|
self.format_choice.SetSelection(0)
|
||||||
|
self.update_split_option_state()
|
||||||
|
|
||||||
def suggest_output_path(self):
|
def suggest_output_path(self):
|
||||||
in_path = self.input_picker.GetPath()
|
in_path = self.input_picker.GetPath()
|
||||||
@@ -140,6 +160,13 @@ class ConverterFrame(wx.Frame):
|
|||||||
base, _ = os.path.splitext(in_path)
|
base, _ = os.path.splitext(in_path)
|
||||||
suggested = base + "." + out_ext
|
suggested = base + "." + out_ext
|
||||||
self.output_picker.SetPath(suggested)
|
self.output_picker.SetPath(suggested)
|
||||||
|
self.update_split_option_state()
|
||||||
|
|
||||||
|
def update_split_option_state(self):
|
||||||
|
is_mp3 = self.format_choice.GetStringSelection().lower() == "mp3"
|
||||||
|
self.split_mp3_choice.Enable(is_mp3)
|
||||||
|
if not is_mp3:
|
||||||
|
self.split_mp3_choice.SetSelection(0)
|
||||||
|
|
||||||
def build_player(self, panel):
|
def build_player(self, panel):
|
||||||
player = wx.BoxSizer(wx.VERTICAL)
|
player = wx.BoxSizer(wx.VERTICAL)
|
||||||
@@ -149,14 +176,44 @@ class ConverterFrame(wx.Frame):
|
|||||||
controls.Add(self.stop_btn, 0, wx.RIGHT, 8)
|
controls.Add(self.stop_btn, 0, wx.RIGHT, 8)
|
||||||
controls.Add(self.time_label, 0, wx.ALIGN_CENTER_VERTICAL)
|
controls.Add(self.time_label, 0, wx.ALIGN_CENTER_VERTICAL)
|
||||||
|
|
||||||
player.Add(wx.StaticText(panel, label="Audio Player"), 0, wx.BOTTOM, 4)
|
|
||||||
player.Add(self.media, 0, wx.EXPAND | wx.BOTTOM, 6)
|
player.Add(self.media, 0, wx.EXPAND | wx.BOTTOM, 6)
|
||||||
player.Add(self.position_slider, 0, wx.EXPAND | wx.BOTTOM, 6)
|
player.Add(self.position_slider, 0, wx.EXPAND | wx.BOTTOM, 6)
|
||||||
player.Add(controls, 0, wx.EXPAND | wx.BOTTOM, 4)
|
player.Add(controls, 0, wx.EXPAND | wx.BOTTOM, 4)
|
||||||
player.Add(self.hotkeys_label, 0)
|
|
||||||
|
|
||||||
return player
|
return player
|
||||||
|
|
||||||
|
def add_labeled_control(self, panel, parent_sizer, label, control, accessible_name=None):
|
||||||
|
label_ctrl = wx.StaticText(panel, label=label)
|
||||||
|
label_ctrl.SetForegroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT))
|
||||||
|
clean_label = label.replace("&", "")
|
||||||
|
if accessible_name is None:
|
||||||
|
accessible_name = clean_label
|
||||||
|
# Keep a stable, human-readable name/description for assistive technologies.
|
||||||
|
control.SetName(accessible_name)
|
||||||
|
control.SetHelpText(accessible_name)
|
||||||
|
label_ctrl.SetName(clean_label)
|
||||||
|
# Keep label and field adjacent in tab order for native AT label lookup.
|
||||||
|
if hasattr(label_ctrl, "MoveBeforeInTabOrder"):
|
||||||
|
label_ctrl.MoveBeforeInTabOrder(control)
|
||||||
|
field_sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
|
field_sizer.Add(label_ctrl, 0, wx.BOTTOM, 2)
|
||||||
|
field_sizer.Add(control, 0, wx.EXPAND)
|
||||||
|
parent_sizer.Add(field_sizer, 0, wx.EXPAND | wx.BOTTOM, 6)
|
||||||
|
|
||||||
|
def configure_file_picker_accessibility(self, picker, label):
|
||||||
|
picker.SetName(label)
|
||||||
|
picker.SetHelpText(label)
|
||||||
|
|
||||||
|
text_ctrl = picker.GetTextCtrl()
|
||||||
|
if text_ctrl:
|
||||||
|
text_ctrl.SetName(f"{label} path")
|
||||||
|
text_ctrl.SetHelpText(label)
|
||||||
|
|
||||||
|
button = picker.GetPickerCtrl()
|
||||||
|
if button:
|
||||||
|
button.SetName(f"Browse {label}")
|
||||||
|
button.SetHelpText(f"Browse {label}")
|
||||||
|
|
||||||
def setup_hotkeys(self):
|
def setup_hotkeys(self):
|
||||||
self.ID_PLAYPAUSE = wx.NewIdRef()
|
self.ID_PLAYPAUSE = wx.NewIdRef()
|
||||||
self.ID_STOP = wx.NewIdRef()
|
self.ID_STOP = wx.NewIdRef()
|
||||||
@@ -305,6 +362,7 @@ class ConverterFrame(wx.Frame):
|
|||||||
self.log_ctrl.Clear()
|
self.log_ctrl.Clear()
|
||||||
self.status.SetLabel("Running...")
|
self.status.SetLabel("Running...")
|
||||||
self.start_btn.Disable()
|
self.start_btn.Disable()
|
||||||
|
self.reset_progress()
|
||||||
|
|
||||||
thread = threading.Thread(target=self.run_ffmpeg, args=(in_path, out_path), daemon=True)
|
thread = threading.Thread(target=self.run_ffmpeg, args=(in_path, out_path), daemon=True)
|
||||||
thread.start()
|
thread.start()
|
||||||
@@ -313,9 +371,27 @@ class ConverterFrame(wx.Frame):
|
|||||||
mode = self.mode_choice.GetStringSelection()
|
mode = self.mode_choice.GetStringSelection()
|
||||||
a_bitrate = self.audio_bitrate.GetValue().strip()
|
a_bitrate = self.audio_bitrate.GetValue().strip()
|
||||||
v_bitrate = self.video_bitrate.GetValue().strip()
|
v_bitrate = self.video_bitrate.GetValue().strip()
|
||||||
|
activation_bytes = self.activation_bytes.GetValue().strip()
|
||||||
copy = self.copy_streams.GetValue()
|
copy = self.copy_streams.GetValue()
|
||||||
|
split_mp3 = self.split_mp3_choice.GetStringSelection().lower() == "yes"
|
||||||
|
output_format = self.format_choice.GetStringSelection().lower()
|
||||||
|
should_split_mp3 = split_mp3 and output_format == "mp3"
|
||||||
|
|
||||||
cmd = ["ffmpeg", "-y", "-i", in_path]
|
duration = self.get_media_duration(in_path)
|
||||||
|
self.prepare_progress(duration)
|
||||||
|
|
||||||
|
cmd = ["ffmpeg", "-y"]
|
||||||
|
cmd += ["-progress", "pipe:1", "-nostats"]
|
||||||
|
if activation_bytes:
|
||||||
|
cmd += ["-activation_bytes", activation_bytes]
|
||||||
|
aaxc_key, aaxc_iv = self.get_aaxc_key_iv(in_path)
|
||||||
|
if aaxc_key and aaxc_iv:
|
||||||
|
cmd += ["-audible_key", aaxc_key, "-audible_iv", aaxc_iv]
|
||||||
|
elif os.path.splitext(in_path)[1].lower() == ".aaxc":
|
||||||
|
self.append_log("Missing or invalid .voucher key/iv for .aaxc file.")
|
||||||
|
self.finish("Failed")
|
||||||
|
return
|
||||||
|
cmd += ["-i", in_path]
|
||||||
|
|
||||||
if mode == "Audio":
|
if mode == "Audio":
|
||||||
cmd.append("-vn")
|
cmd.append("-vn")
|
||||||
@@ -332,7 +408,26 @@ class ConverterFrame(wx.Frame):
|
|||||||
if a_bitrate:
|
if a_bitrate:
|
||||||
cmd += ["-b:a", a_bitrate]
|
cmd += ["-b:a", a_bitrate]
|
||||||
|
|
||||||
cmd.append(out_path)
|
if should_split_mp3:
|
||||||
|
chapter_times = self.get_chapter_end_times(in_path)
|
||||||
|
if chapter_times:
|
||||||
|
output_pattern = self.build_capture_output_pattern(out_path)
|
||||||
|
cmd += [
|
||||||
|
"-f",
|
||||||
|
"segment",
|
||||||
|
"-segment_times",
|
||||||
|
",".join(chapter_times),
|
||||||
|
"-reset_timestamps",
|
||||||
|
"1",
|
||||||
|
"-segment_format",
|
||||||
|
"mp3",
|
||||||
|
output_pattern,
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.append_log("No chapter markers found; writing a single MP3 file.")
|
||||||
|
cmd.append(out_path)
|
||||||
|
else:
|
||||||
|
cmd.append(out_path)
|
||||||
|
|
||||||
self.append_log("Command: " + " ".join(cmd))
|
self.append_log("Command: " + " ".join(cmd))
|
||||||
|
|
||||||
@@ -346,9 +441,14 @@ class ConverterFrame(wx.Frame):
|
|||||||
universal_newlines=True,
|
universal_newlines=True,
|
||||||
)
|
)
|
||||||
for line in proc.stdout:
|
for line in proc.stdout:
|
||||||
self.append_log(line.rstrip())
|
line = line.rstrip()
|
||||||
|
if self.handle_progress_line(line, duration):
|
||||||
|
continue
|
||||||
|
if line:
|
||||||
|
self.append_log(line)
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode == 0:
|
if proc.returncode == 0:
|
||||||
|
self.set_progress_complete()
|
||||||
self.finish("Done")
|
self.finish("Done")
|
||||||
else:
|
else:
|
||||||
self.finish("Failed")
|
self.finish("Failed")
|
||||||
@@ -363,6 +463,166 @@ class ConverterFrame(wx.Frame):
|
|||||||
wx.CallAfter(self.status.SetLabel, status_text)
|
wx.CallAfter(self.status.SetLabel, status_text)
|
||||||
wx.CallAfter(self.start_btn.Enable)
|
wx.CallAfter(self.start_btn.Enable)
|
||||||
|
|
||||||
|
def reset_progress(self):
|
||||||
|
self.progress_gauge.SetRange(1000)
|
||||||
|
self.progress_gauge.SetValue(0)
|
||||||
|
|
||||||
|
def prepare_progress(self, duration_seconds):
|
||||||
|
if duration_seconds and duration_seconds > 0:
|
||||||
|
wx.CallAfter(self.progress_gauge.SetRange, 1000)
|
||||||
|
wx.CallAfter(self.progress_gauge.SetValue, 0)
|
||||||
|
else:
|
||||||
|
wx.CallAfter(self.progress_gauge.Pulse)
|
||||||
|
|
||||||
|
def set_progress_value(self, ratio):
|
||||||
|
ratio = max(0.0, min(1.0, ratio))
|
||||||
|
value = int(ratio * 1000)
|
||||||
|
wx.CallAfter(self.progress_gauge.SetValue, value)
|
||||||
|
|
||||||
|
def set_progress_complete(self):
|
||||||
|
wx.CallAfter(self.progress_gauge.SetValue, 1000)
|
||||||
|
|
||||||
|
def handle_progress_line(self, line, duration_seconds):
|
||||||
|
if not line:
|
||||||
|
return False
|
||||||
|
if line.startswith("out_time_ms="):
|
||||||
|
if duration_seconds and duration_seconds > 0:
|
||||||
|
try:
|
||||||
|
out_ms = int(line.split("=", 1)[1].strip())
|
||||||
|
ratio = out_ms / (duration_seconds * 1_000_000)
|
||||||
|
self.set_progress_value(ratio)
|
||||||
|
except (ValueError, ZeroDivisionError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
wx.CallAfter(self.progress_gauge.Pulse)
|
||||||
|
return True
|
||||||
|
if line.startswith("progress="):
|
||||||
|
if line.split("=", 1)[1].strip() == "end":
|
||||||
|
self.set_progress_complete()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_media_duration(self, in_path):
|
||||||
|
if not shutil.which("ffprobe"):
|
||||||
|
return 0
|
||||||
|
cmd = [
|
||||||
|
"ffprobe",
|
||||||
|
"-v",
|
||||||
|
"error",
|
||||||
|
"-show_entries",
|
||||||
|
"format=duration",
|
||||||
|
"-of",
|
||||||
|
"default=nk=1:nw=1",
|
||||||
|
in_path,
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
proc = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
return 0
|
||||||
|
value = (proc.stdout or "").strip()
|
||||||
|
return float(value) if value else 0
|
||||||
|
except Exception:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_aaxc_key_iv(self, in_path):
|
||||||
|
if os.path.splitext(in_path)[1].lower() != ".aaxc":
|
||||||
|
return None, None
|
||||||
|
voucher_path = os.path.splitext(in_path)[0] + ".voucher"
|
||||||
|
if not os.path.isfile(voucher_path):
|
||||||
|
return None, None
|
||||||
|
try:
|
||||||
|
with open(voucher_path, "r", encoding="utf-8") as handle:
|
||||||
|
data = json.load(handle)
|
||||||
|
except Exception:
|
||||||
|
return None, None
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
# Support multiple voucher shapes:
|
||||||
|
# - content_license.license_response (current Audible export shape)
|
||||||
|
# - lilicense_response (legacy/typo compatibility)
|
||||||
|
# - license_response (flat shape fallback)
|
||||||
|
license_resp = None
|
||||||
|
content_license = data.get("content_license")
|
||||||
|
if isinstance(content_license, dict):
|
||||||
|
candidate = content_license.get("license_response")
|
||||||
|
if isinstance(candidate, dict):
|
||||||
|
license_resp = candidate
|
||||||
|
if license_resp is None:
|
||||||
|
candidate = data.get("lilicense_response")
|
||||||
|
if isinstance(candidate, dict):
|
||||||
|
license_resp = candidate
|
||||||
|
if license_resp is None:
|
||||||
|
candidate = data.get("license_response")
|
||||||
|
if isinstance(candidate, dict):
|
||||||
|
license_resp = candidate
|
||||||
|
if not isinstance(license_resp, dict):
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
key = license_resp.get("key")
|
||||||
|
iv = license_resp.get("iv")
|
||||||
|
if not key or not iv:
|
||||||
|
return None, None
|
||||||
|
return str(key), str(iv)
|
||||||
|
|
||||||
|
def build_capture_output_pattern(self, out_path):
|
||||||
|
base, ext = os.path.splitext(out_path)
|
||||||
|
return f"{base}_capture_%03d{ext}"
|
||||||
|
|
||||||
|
def get_chapter_end_times(self, in_path):
|
||||||
|
if not shutil.which("ffprobe"):
|
||||||
|
self.append_log("ffprobe not found on PATH; cannot split by chapters.")
|
||||||
|
return []
|
||||||
|
cmd = [
|
||||||
|
"ffprobe",
|
||||||
|
"-v",
|
||||||
|
"error",
|
||||||
|
"-print_format",
|
||||||
|
"json",
|
||||||
|
"-show_chapters",
|
||||||
|
"-i",
|
||||||
|
in_path,
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
proc = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
text=True,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
self.append_log("ffprobe failed; cannot split by chapters.")
|
||||||
|
return []
|
||||||
|
data = json.loads(proc.stdout or "{}")
|
||||||
|
except Exception as exc:
|
||||||
|
self.append_log(f"ffprobe error: {exc}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
chapters = data.get("chapters", [])
|
||||||
|
end_times = []
|
||||||
|
for chapter in chapters:
|
||||||
|
end_time = chapter.get("end_time")
|
||||||
|
if end_time is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
end_times.append(float(end_time))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
if len(end_times) <= 1:
|
||||||
|
return []
|
||||||
|
end_times = end_times[:-1]
|
||||||
|
formatted = []
|
||||||
|
for value in end_times:
|
||||||
|
formatted.append(f"{value:.3f}".rstrip("0").rstrip("."))
|
||||||
|
return formatted
|
||||||
|
|
||||||
|
|
||||||
class App(wx.App):
|
class App(wx.App):
|
||||||
def OnInit(self):
|
def OnInit(self):
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
wxPython>=4.2.1
|
|
||||||
Reference in New Issue
Block a user