2 Commits
1.2 ... main

Author SHA1 Message Date
45a1f34c00 changed the environment to pipenv 2026-02-15 18:33:09 +01:00
6256ba597e added support for .aaxc files. 2026-02-13 18:31:01 +01:00
13 changed files with 300 additions and 100 deletions

3
.gitignore vendored
View File

@@ -22,4 +22,5 @@ Thumbs.db
.idea/
# Logs
*.log
*.log
*.lock

13
Pipfile Normal file
View 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
View 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.

View File

@@ -380,18 +380,6 @@
('pathlib._abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.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'),
('__future__',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
'PYMODULE'),
@@ -503,18 +491,18 @@
('multiprocessing',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\multiprocessing\\__init__.py',
'PYMODULE'),
('_colorize',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
'PYMODULE'),
('_colorize',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
'PYMODULE'),
('_py_abc',
'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'),
@@ -670,6 +658,18 @@
'PYMODULE'),
('_threading_local',
'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')],
[('python313.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
@@ -749,82 +749,34 @@
('wx\\wxmsw32u_core_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'),
('wx\\wxbase32u_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
'BINARY'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('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')],
[('posixpath',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\posixpath.py',
[('io',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\io.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',
('operator',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\operator.py',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py',
'PYMODULE'),
('functools',
'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'),
('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_parse',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_parse.py',
'PYMODULE'),
('encodings.zlib_codec',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\zlib_codec.py',
'PYMODULE'),
@@ -1191,18 +1143,51 @@
('encodings',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\encodings\\__init__.py',
'PYMODULE'),
('sre_compile',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_compile.py',
('sre_constants',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\sre_constants.py',
'PYMODULE'),
('weakref',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\weakref.py',
('collections.abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\abc.py',
'PYMODULE'),
('heapq',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\heapq.py',
('collections',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\collections\\__init__.py',
'PYMODULE'),
('keyword',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\reprlib.py',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\_parser.py',
'PYMODULE'),
@@ -1218,17 +1203,32 @@
('re',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\re\\__init__.py',
'PYMODULE'),
('keyword',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\keyword.py',
('_weakrefset',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_weakrefset.py',
'PYMODULE'),
('abc',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\abc.py',
'PYMODULE'),
('locale',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\locale.py',
'PYMODULE'),
('weakref',
'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'),
('operator',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\operator.py',
('ntpath',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ntpath.py',
'PYMODULE'),
('warnings',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\warnings.py',
('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'),
('os',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\os.py',

View File

@@ -136,27 +136,27 @@
('wx\\wxmsw32u_core_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_core_vc140_x64.dll',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'),
('wx\\wxbase32u_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_vc140_x64.dll',
'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',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxmsw32u_html_vc140_x64.dll',
'BINARY'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('wx\\wxbase32u_net_vc140_x64.dll',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\wx\\wxbase32u_net_vc140_x64.dll',
'BINARY'),
('MSVCP140.dll', 'C:\\Windows\\System32\\MSVCP140.dll', 'BINARY'),
('base_library.zip', 'D:\\audio\\build\\main\\base_library.zip', 'DATA')],
[],
False,
False,
1770832619,
1770922631,
[('run.exe',
'C:\\Users\\aaron\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
'EXECUTABLE')],

View File

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

Binary file not shown.

Binary file not shown.

View File

@@ -152,6 +152,7 @@ imports:
&#8226; <a href="#genericpath">genericpath</a>
&#8226; <a href="#heapq">heapq</a>
&#8226; <a href="#io">io</a>
&#8226; <a href="#json">json</a>
&#8226; <a href="#keyword">keyword</a>
&#8226; <a href="#linecache">linecache</a>
&#8226; <a href="#locale">locale</a>
@@ -7206,6 +7207,7 @@ imported by:
&#8226; <a href="#json.decoder">json.decoder</a>
&#8226; <a href="#json.encoder">json.encoder</a>
&#8226; <a href="#json.scanner">json.scanner</a>
&#8226; <a href="#main.py">main.py</a>
</div>

BIN
dist/main.exe vendored

Binary file not shown.

135
main.py
View File

@@ -6,7 +6,7 @@ import subprocess
import wx
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"]
@@ -41,6 +41,10 @@ class ConverterFrame(wx.Frame):
self.log_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY)
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.play_btn = wx.Button(panel, label="&Play/Pause")
@@ -101,6 +105,8 @@ class ConverterFrame(wx.Frame):
main.Add(form, 0, wx.EXPAND | wx.ALL, 10)
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, 10)
main.Add(self.progress_label, 0, wx.LEFT | wx.RIGHT | wx.BOTTOM, 4)
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)
@@ -356,6 +362,7 @@ class ConverterFrame(wx.Frame):
self.log_ctrl.Clear()
self.status.SetLabel("Running...")
self.start_btn.Disable()
self.reset_progress()
thread = threading.Thread(target=self.run_ffmpeg, args=(in_path, out_path), daemon=True)
thread.start()
@@ -370,9 +377,20 @@ class ConverterFrame(wx.Frame):
output_format = self.format_choice.GetStringSelection().lower()
should_split_mp3 = split_mp3 and output_format == "mp3"
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":
@@ -423,9 +441,14 @@ class ConverterFrame(wx.Frame):
universal_newlines=True,
)
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()
if proc.returncode == 0:
self.set_progress_complete()
self.finish("Done")
else:
self.finish("Failed")
@@ -440,6 +463,114 @@ class ConverterFrame(wx.Frame):
wx.CallAfter(self.status.SetLabel, status_text)
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}"

View File

@@ -1 +0,0 @@
wxPython>=4.2.1