4 Commits
1.1 ... 1.2

Author SHA1 Message Date
47b452fe5f added capture support for audio files. 2026-02-12 15:02:47 +01:00
5d7599891c added an edit box for the activation_bytes(used for encrypted files) and made some labels 2026-02-11 23:03:39 +01:00
eb9d4c8cf9 removed actions 2026-02-11 19:13:12 +01:00
123a2126ee added a .gitignore
All checks were successful
PyInstaller Build / build (push) Successful in 2m27s
2026-02-11 19:01:59 +01:00
13 changed files with 343 additions and 176 deletions

View File

@@ -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

25
.gitignore vendored Normal file
View File

@@ -0,0 +1,25 @@
# 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

View File

@@ -503,17 +503,20 @@
('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'),
('_colorize',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
'PYMODULE'),
('_py_abc', ('_py_abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
'PYMODULE'), 'PYMODULE'),
('stringprep',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
'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',
'PYMODULE'), 'PYMODULE'),
('_colorize', ('wx.media',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\media.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.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',
@@ -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,45 +737,84 @@
('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'),
('wx\\wxmsw32u_core_vc140_x64.dll', ('wx\\wxmsw32u_core_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
'BINARY'),
('VCRUNTIME140_1.dll', ('VCRUNTIME140_1.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll', ('wx\\wxmsw32u_media_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\\wxmsw32u_media_vc140_x64.dll',
'BINARY'), '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'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('wx\\wxbase32u_net_vc140_x64.dll', ('wx\\wxbase32u_net_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll',
'BINARY'), 'BINARY')],
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY')],
[], [],
[], [],
[('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')], [('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
[('_collections_abc', [('posixpath',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\posixpath.py',
'PYMODULE'),
('copyreg',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copyreg.py',
'PYMODULE'),
('reprlib',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\reprlib.py',
'PYMODULE'),
('linecache',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\linecache.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', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_collections_abc.py',
'PYMODULE'), 'PYMODULE'),
('types',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\types.py',
'PYMODULE'),
('genericpath',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\genericpath.py',
'PYMODULE'),
('traceback',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\traceback.py',
'PYMODULE'),
('codecs',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\codecs.py',
'PYMODULE'),
('_weakrefset', ('_weakrefset',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py',
'PYMODULE'), 'PYMODULE'),
('ntpath',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ntpath.py',
'PYMODULE'),
('io',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\io.py',
'PYMODULE'),
('abc', ('abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py',
'PYMODULE'), 'PYMODULE'),
('sre_constants', ('functools',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_constants.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\functools.py',
'PYMODULE'),
('locale',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\locale.py',
'PYMODULE'), 'PYMODULE'),
('collections.abc', ('collections.abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\abc.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\abc.py',
@@ -777,30 +822,9 @@
('collections', ('collections',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\__init__.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\__init__.py',
'PYMODULE'), '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'),
('types',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\types.py',
'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', ('sre_parse',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_parse.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_parse.py',
'PYMODULE'), '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,23 +1191,17 @@
('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_compile',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\linecache.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_compile.py',
'PYMODULE'), 'PYMODULE'),
('codecs', ('weakref',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\codecs.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\weakref.py',
'PYMODULE'), 'PYMODULE'),
('genericpath', ('heapq',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\genericpath.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\heapq.py',
'PYMODULE'), 'PYMODULE'),
('copyreg', ('enum',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copyreg.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\enum.py',
'PYMODULE'),
('keyword',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
'PYMODULE'),
('reprlib',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\reprlib.py',
'PYMODULE'), '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',
@@ -1200,26 +1218,17 @@
('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', ('keyword',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\heapq.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
'PYMODULE'),
('functools',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\functools.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'), 'PYMODULE'),
('stat', ('stat',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stat.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stat.py',
'PYMODULE'), 'PYMODULE'),
('locale', ('operator',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\locale.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\operator.py',
'PYMODULE'), 'PYMODULE'),
('posixpath', ('warnings',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\posixpath.py', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\warnings.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',

View File

@@ -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,36 +124,39 @@
('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'),
('wx\\wxmsw32u_core_vc140_x64.dll', ('wx\\wxmsw32u_core_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
'BINARY'),
('VCRUNTIME140_1.dll', ('VCRUNTIME140_1.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll', ('wx\\wxmsw32u_media_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\\wxmsw32u_media_vc140_x64.dll',
'BINARY'), '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'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('wx\\wxbase32u_net_vc140_x64.dll', ('wx\\wxbase32u_net_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll',
'BINARY'), 'BINARY'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')], ('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
[], [],
False, False,
False, False,
1770822014, 1770832619,
[('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')],

View File

@@ -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,31 +102,34 @@
('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'),
('wx\\wxmsw32u_core_vc140_x64.dll', ('wx\\wxmsw32u_core_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
'BINARY'),
('VCRUNTIME140_1.dll', ('VCRUNTIME140_1.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'), 'BINARY'),
('wx\\wxbase32u_vc140_x64.dll', ('wx\\wxmsw32u_media_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\\wxmsw32u_media_vc140_x64.dll',
'BINARY'), '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'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('wx\\wxbase32u_net_vc140_x64.dll', ('wx\\wxbase32u_net_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll', 'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll',
'BINARY'), 'BINARY'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')], ('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
'python313.dll', 'python313.dll',
False, False,

Binary file not shown.

View File

@@ -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.

View File

@@ -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)

View File

@@ -180,6 +180,7 @@ imports:
&#8226; <a href="#warnings">warnings</a> &#8226; <a href="#warnings">warnings</a>
&#8226; <a href="#weakref">weakref</a> &#8226; <a href="#weakref">weakref</a>
&#8226; <a href="#wx">wx</a> &#8226; <a href="#wx">wx</a>
&#8226; <a href="#wx.media">wx.media</a>
</div> </div>
@@ -10346,12 +10347,14 @@ imported by:
&#8226; <a href="#wx._adv">wx._adv</a> &#8226; <a href="#wx._adv">wx._adv</a>
&#8226; <a href="#wx._core">wx._core</a> &#8226; <a href="#wx._core">wx._core</a>
&#8226; <a href="#wx._html">wx._html</a> &#8226; <a href="#wx._html">wx._html</a>
&#8226; <a href="#wx._media">wx._media</a>
&#8226; <a href="#wx._msw">wx._msw</a> &#8226; <a href="#wx._msw">wx._msw</a>
&#8226; <a href="#wx.adv">wx.adv</a> &#8226; <a href="#wx.adv">wx.adv</a>
&#8226; <a href="#wx.core">wx.core</a> &#8226; <a href="#wx.core">wx.core</a>
&#8226; <a href="#wx.html">wx.html</a> &#8226; <a href="#wx.html">wx.html</a>
&#8226; <a href="#wx.lib">wx.lib</a> &#8226; <a href="#wx.lib">wx.lib</a>
&#8226; <a href="#wx.lib.colourutils">wx.lib.colourutils</a> &#8226; <a href="#wx.lib.colourutils">wx.lib.colourutils</a>
&#8226; <a href="#wx.media">wx.media</a>
&#8226; <a href="#wx.msw">wx.msw</a> &#8226; <a href="#wx.msw">wx.msw</a>
&#8226; <a href="#wx.siplib">wx.siplib</a> &#8226; <a href="#wx.siplib">wx.siplib</a>
@@ -10421,6 +10424,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 +10556,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>
&#8226; <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

Binary file not shown.

227
main.py
View File

@@ -1,4 +1,5 @@
import os import os
import json
import threading import threading
import shutil import shutil
import subprocess import subprocess
@@ -11,10 +12,15 @@ 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,26 @@ 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.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 +57,52 @@ 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.log_ctrl, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 10)
main.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 12) main.Add(self.status, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 10)
panel.SetSizer(main) panel.SetSizer(main)
@@ -131,6 +144,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 +154,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 +170,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()
@@ -313,9 +364,16 @@ 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] cmd = ["ffmpeg", "-y"]
if activation_bytes:
cmd += ["-activation_bytes", activation_bytes]
cmd += ["-i", in_path]
if mode == "Audio": if mode == "Audio":
cmd.append("-vn") cmd.append("-vn")
@@ -332,6 +390,25 @@ class ConverterFrame(wx.Frame):
if a_bitrate: if a_bitrate:
cmd += ["-b:a", a_bitrate] cmd += ["-b:a", a_bitrate]
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) cmd.append(out_path)
self.append_log("Command: " + " ".join(cmd)) self.append_log("Command: " + " ".join(cmd))
@@ -363,6 +440,58 @@ 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 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):