TonieToolbox 0.1.6__py3-none-any.whl → 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
TonieToolbox/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  TonieToolbox - Convert audio files to Tonie box compatible format
3
3
  """
4
4
 
5
- __version__ = '0.1.6'
5
+ __version__ = '0.1.7'
TonieToolbox/__main__.py CHANGED
@@ -89,10 +89,13 @@ def main():
89
89
  # Check for updates
90
90
  if not args.skip_update_check:
91
91
  logger.debug("Checking for updates (force_refresh=%s)", args.force_refresh_cache)
92
- check_for_updates(
92
+ is_latest, latest_version, message, update_confirmed = check_for_updates(
93
93
  quiet=args.silent or args.quiet,
94
94
  force_refresh=args.force_refresh_cache
95
95
  )
96
+
97
+ if not is_latest and not update_confirmed and not (args.silent or args.quiet):
98
+ logger.info("Update available but user chose to continue without updating.")
96
99
 
97
100
  ffmpeg_binary = args.ffmpeg
98
101
  if ffmpeg_binary is None:
@@ -309,14 +309,65 @@ def ensure_dependency(dependency_name, auto_download=False):
309
309
  logger.info("Found %s in PATH: %s", dependency_name, path_binary)
310
310
  return path_binary
311
311
 
312
+ # Set up paths to check for previously downloaded versions
313
+ user_data_dir = get_user_data_dir()
314
+ dependency_info = DEPENDENCIES[dependency_name].get(system, {})
315
+ extract_dir_name = dependency_info.get('extract_dir', dependency_name)
316
+ binary_path = dependency_info.get('bin_path', bin_name)
317
+ extract_dir = os.path.join(user_data_dir, extract_dir_name)
318
+
319
+ # Check if we already downloaded and extracted it previously
320
+ logger.debug("Checking for previously downloaded %s in %s", dependency_name, extract_dir)
321
+ if os.path.exists(extract_dir):
322
+ existing_binary = find_binary_in_extracted_dir(extract_dir, binary_path)
323
+ if existing_binary and os.path.exists(existing_binary):
324
+ # Verify that the binary works
325
+ logger.info("Found previously downloaded %s: %s", dependency_name, existing_binary)
326
+ try:
327
+ if os.access(existing_binary, os.X_OK) or system == 'windows':
328
+ if system in ['linux', 'darwin']:
329
+ logger.debug("Ensuring executable permissions on %s", existing_binary)
330
+ os.chmod(existing_binary, 0o755)
331
+
332
+ # Quick check to verify binary works
333
+ if dependency_name == 'opusenc':
334
+ cmd = [existing_binary, '--version']
335
+ try:
336
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=5)
337
+ if result.returncode == 0:
338
+ logger.info("Using previously downloaded %s: %s", dependency_name, existing_binary)
339
+ return existing_binary
340
+ except:
341
+ # If --version fails, try without arguments
342
+ try:
343
+ result = subprocess.run([existing_binary], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=5)
344
+ if result.returncode == 0:
345
+ logger.info("Using previously downloaded %s: %s", dependency_name, existing_binary)
346
+ return existing_binary
347
+ except:
348
+ pass
349
+ else:
350
+ cmd = [existing_binary, '-version']
351
+ try:
352
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=5)
353
+ if result.returncode == 0:
354
+ logger.info("Using previously downloaded %s: %s", dependency_name, existing_binary)
355
+ return existing_binary
356
+ except:
357
+ pass
358
+
359
+ logger.warning("Previously downloaded %s exists but failed verification", dependency_name)
360
+ except Exception as e:
361
+ logger.warning("Error verifying downloaded binary: %s", e)
362
+
312
363
  # If auto_download is not enabled, don't try to install or download
313
364
  if not auto_download:
314
365
  logger.warning("%s not found in PATH and auto-download is disabled. Use --auto-download to enable automatic installation.", dependency_name)
315
366
  return None
316
367
 
317
368
  # If not in PATH, check if we should install via package manager
318
- if 'package' in DEPENDENCIES[dependency_name].get(system, {}):
319
- package_name = DEPENDENCIES[dependency_name][system]['package']
369
+ if 'package' in dependency_info:
370
+ package_name = dependency_info['package']
320
371
  logger.info("%s not found. Attempting to install %s package...", dependency_name, package_name)
321
372
  if install_package(package_name):
322
373
  path_binary = check_binary_in_path(bin_name)
@@ -325,27 +376,14 @@ def ensure_dependency(dependency_name, auto_download=False):
325
376
  return path_binary
326
377
 
327
378
  # If not installable via package manager or installation failed, try downloading
328
- if 'url' not in DEPENDENCIES[dependency_name].get(system, {}):
379
+ if 'url' not in dependency_info:
329
380
  logger.error("Cannot download %s for %s", dependency_name, system)
330
381
  return None
331
382
 
332
- # Set up paths
333
- user_data_dir = get_user_data_dir()
334
- dependency_info = DEPENDENCIES[dependency_name][system]
383
+ # Set up download paths
335
384
  download_url = dependency_info['url']
336
- extract_dir_name = dependency_info['extract_dir']
337
- binary_path = dependency_info['bin_path']
338
-
339
- extract_dir = os.path.join(user_data_dir, extract_dir_name)
340
- logger.debug("Using extract directory: %s", extract_dir)
341
385
  os.makedirs(extract_dir, exist_ok=True)
342
386
 
343
- # Check if we already downloaded and extracted it
344
- existing_binary = find_binary_in_extracted_dir(extract_dir, binary_path)
345
- if existing_binary and os.path.exists(existing_binary):
346
- logger.info("Using existing %s: %s", dependency_name, existing_binary)
347
- return existing_binary
348
-
349
387
  # Download and extract
350
388
  archive_ext = '.zip' if download_url.endswith('zip') else '.tar.xz'
351
389
  archive_path = os.path.join(user_data_dir, f"{dependency_name}{archive_ext}")
@@ -134,24 +134,27 @@ def check_for_updates(quiet=False, force_refresh=False):
134
134
  Check if the current version of TonieToolbox is the latest.
135
135
 
136
136
  Args:
137
- quiet: If True, will not log any information messages
137
+ quiet: If True, will not log any information messages and skip user confirmation
138
138
  force_refresh: If True, bypass cache and check PyPI directly
139
139
 
140
140
  Returns:
141
- tuple: (is_latest, latest_version, message)
141
+ tuple: (is_latest, latest_version, message, update_confirmed)
142
142
  is_latest: boolean indicating if the current version is the latest
143
143
  latest_version: string with the latest version
144
144
  message: string message about the update status or error
145
+ update_confirmed: boolean indicating if the user confirmed the update
145
146
  """
146
147
  logger = get_logger("version_handler")
147
148
  current_version = __version__
149
+ update_confirmed = False
148
150
 
149
- logger.debug("Starting update check (quiet=%s, force_refresh=%s)", quiet, force_refresh)
151
+ logger.debug("Starting update check (quiet=%s, force_refresh=%s)",
152
+ quiet, force_refresh)
150
153
  latest_version, error = get_pypi_version(force_refresh)
151
154
 
152
155
  if error:
153
156
  logger.debug("Error occurred during update check: %s", error)
154
- return True, current_version, error
157
+ return True, current_version, error, update_confirmed
155
158
 
156
159
  compare_result = compare_versions(current_version, latest_version)
157
160
  is_latest = compare_result >= 0 # current >= latest
@@ -166,9 +169,69 @@ def check_for_updates(quiet=False, force_refresh=False):
166
169
  message = f"Update available! Current version: {current_version}, Latest version: {latest_version}"
167
170
  if not quiet:
168
171
  logger.info(message)
169
- logger.info("Consider upgrading with: pip install --upgrade TonieToolbox")
172
+
173
+ # Show confirmation prompt if not in quiet mode
174
+ try:
175
+ response = input(f"Do you want to upgrade to TonieToolbox {latest_version}? [y/N]: ").lower().strip()
176
+ update_confirmed = response == 'y' or response == 'yes'
177
+
178
+ if update_confirmed:
179
+ logger.info("Update confirmed. Attempting to install update...")
180
+ if install_update():
181
+ logger.info(f"Successfully updated to TonieToolbox {latest_version}")
182
+ import sys
183
+ logger.info("Exiting program. Please restart TonieToolbox to use the new version.")
184
+ sys.exit(0)
185
+ else:
186
+ logger.error("Failed to install update automatically")
187
+ logger.error("Please update manually using: pip install --upgrade TonieToolbox")
188
+ import sys
189
+ sys.exit(1)
190
+ else:
191
+ logger.info("Update skipped by user.")
192
+ except (EOFError, KeyboardInterrupt):
193
+ logger.debug("User input interrupted")
194
+ update_confirmed = False
195
+
196
+ return is_latest, latest_version, message, update_confirmed
197
+
198
+
199
+ def install_update():
200
+ """
201
+ Try to install the update using pip, pip3, or pipx.
202
+
203
+ Returns:
204
+ bool: True if the update was successfully installed, False otherwise
205
+ """
206
+ logger = get_logger("version_handler")
207
+ import subprocess
208
+ import sys
209
+
210
+ package_name = "TonieToolbox"
211
+ commands = [
212
+ [sys.executable, "-m", "pip", "install", "--upgrade", package_name],
213
+ ["pip", "install", "--upgrade", package_name],
214
+ ["pip3", "install", "--upgrade", package_name],
215
+ ["pipx", "upgrade", package_name]
216
+ ]
217
+
218
+ for cmd in commands:
219
+ try:
220
+ logger.info(f"Attempting to install update using: {' '.join(cmd)}")
221
+ result = subprocess.run(cmd, capture_output=True, text=True, check=False)
222
+
223
+ if result.returncode == 0:
224
+ logger.debug("Update command succeeded")
225
+ logger.debug(f"Output: {result.stdout}")
226
+ return True
227
+ else:
228
+ logger.debug(f"Command failed with returncode {result.returncode}")
229
+ logger.debug(f"stdout: {result.stdout}")
230
+ logger.debug(f"stderr: {result.stderr}")
231
+ except Exception as e:
232
+ logger.debug(f"Exception while running {cmd[0]}: {str(e)}")
170
233
 
171
- return is_latest, latest_version, message
234
+ return False
172
235
 
173
236
 
174
237
  def clear_version_cache():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TonieToolbox
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: Convert audio files to Tonie box compatible format
5
5
  Home-page: https://github.com/Quentendo64/TonieToolbox
6
6
  Author: Quentendo64
@@ -1,8 +1,8 @@
1
- TonieToolbox/__init__.py,sha256=LTELDMNigo883omB6nSwss4YveBM23FSsESuIQyqSGg,96
2
- TonieToolbox/__main__.py,sha256=zMaoT7-0JUT3PiU5A2xKNgig6NS1PUh4vDKUebJVdYg,8280
1
+ TonieToolbox/__init__.py,sha256=H7iZa88oEbyIf0RTuwe8HaIbX7hDamX8WW6fQubcijs,96
2
+ TonieToolbox/__main__.py,sha256=eEsfnwLsgI6ynwR4uxo4CKptuOJDpGp6lYWSRwJSY3M,8520
3
3
  TonieToolbox/audio_conversion.py,sha256=10PayO1VQDGee2bcO6JD8zRSFoJRJhO2pBeba5k15vk,7998
4
4
  TonieToolbox/constants.py,sha256=QQWQpnCI65GByLlXLOkt2n8nALLu4m6BWp0zuhI3M04,2021
5
- TonieToolbox/dependency_manager.py,sha256=sr7PMBsqQ26bYszM-7Ay-UbKPuBJGyeJV3y1BPAOiBQ,15028
5
+ TonieToolbox/dependency_manager.py,sha256=LHH8PlKp12_TkFFk2dyg6CRURh3-oCOiDff1AIEUbKU,17397
6
6
  TonieToolbox/filename_generator.py,sha256=RqQHyGTKakuWR01yMSnFVMU_HfLw3rqFxKhXNIHdTlg,3441
7
7
  TonieToolbox/logger.py,sha256=Up9fBVkOZwkY61_645bX4tienCpyVSkap-FeTV0v730,1441
8
8
  TonieToolbox/ogg_page.py,sha256=-ViaIRBgh5ayfwmyplL8QmmRr5P36X8W0DdHkSFUYUU,21948
@@ -11,10 +11,10 @@ TonieToolbox/tonie_analysis.py,sha256=4eOzxHL_g0TJFhuexNHcZXivxZ7eb5xfb9-efUZ02W
11
11
  TonieToolbox/tonie_file.py,sha256=nIS4qhpBKIyPvTU39yYljRidpY6cz78halXlz3HJy9w,15294
12
12
  TonieToolbox/tonie_header.proto,sha256=WaWfwO4VrwGtscK2ujfDRKtpeBpaVPoZhI8iMmR-C0U,202
13
13
  TonieToolbox/tonie_header_pb2.py,sha256=s5bp4ULTEekgq6T61z9fDkRavyPM-3eREs20f_Pxxe8,3665
14
- TonieToolbox/version_handler.py,sha256=KU7rS07RL6IZZL2rk4TJ9oKrAutiWvPBOr7qgZLIogI,7108
15
- tonietoolbox-0.1.6.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
16
- tonietoolbox-0.1.6.dist-info/METADATA,sha256=xjwX7xRYP52Vs-flUlTtrxTUlaRMCLMrhtSbw9dOZDo,8971
17
- tonietoolbox-0.1.6.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
18
- tonietoolbox-0.1.6.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
19
- tonietoolbox-0.1.6.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
20
- tonietoolbox-0.1.6.dist-info/RECORD,,
14
+ TonieToolbox/version_handler.py,sha256=7Zx-pgzAUhz6jMplvNal1wHyxidodVxaNcAV0EMph5k,9778
15
+ tonietoolbox-0.1.7.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
16
+ tonietoolbox-0.1.7.dist-info/METADATA,sha256=7kF7ZRqq_GWhRUrw-z6XlxdfG6kY_nTOtlIUfVFk0DU,8971
17
+ tonietoolbox-0.1.7.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
18
+ tonietoolbox-0.1.7.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
19
+ tonietoolbox-0.1.7.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
20
+ tonietoolbox-0.1.7.dist-info/RECORD,,