TonieToolbox 0.6.0a2__py3-none-any.whl → 0.6.0a4__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.
@@ -52,15 +52,19 @@ def handle_config():
52
52
  import platform
53
53
  import subprocess
54
54
 
55
+
55
56
  config_path = os.path.join(os.path.expanduser("~"), ".tonietoolbox", "config.json")
56
-
57
57
  if not os.path.exists(config_path):
58
58
  logger.info(f"Configuration file not found at {config_path}.")
59
59
  logger.info("Creating a new configuration file. Using --install-integration will create a new config file.")
60
60
  return
61
61
  if platform.system() == "Windows":
62
+ from .integration_windows import WindowsClassicContextMenuIntegration as ContextMenuIntegration
63
+ ContextMenuIntegration._apply_config_template()
62
64
  os.startfile(config_path)
63
65
  elif platform.system() == "Darwin":
66
+ from .integration_macos import MacOSContextMenuIntegration as ContextMenuIntegration
67
+ ContextMenuIntegration._apply_config_template()
64
68
  subprocess.call(["open", config_path])
65
69
  elif platform.system() == "Linux":
66
70
  subprocess.call(["xdg-open", config_path])
@@ -1,11 +1,11 @@
1
- # filepath: d:\Repository\TonieToolbox\TonieToolbox\integration_macos.py
2
1
  import os
3
2
  import sys
4
3
  import json
5
4
  import plistlib
6
5
  import subprocess
7
6
  from pathlib import Path
8
- from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE
7
+ from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE,UTI_MAPPINGS,ICON_BASE64
8
+ from .artwork import base64_to_ico
9
9
  from .logger import get_logger
10
10
 
11
11
  logger = get_logger('integration_macos')
@@ -22,15 +22,9 @@ class MacOSContextMenuIntegration:
22
22
  self.services_dir = os.path.join(os.path.expanduser('~'), 'Library', 'Services')
23
23
  self.icon_path = os.path.join(self.output_dir, 'icon.png')
24
24
  os.makedirs(self.output_dir, exist_ok=True)
25
-
26
- # Error handling and success messages for shell scripts
27
25
  self.error_handling = 'if [ $? -ne 0 ]; then\n echo "Error: Command failed with error code $?"\n read -p "Press any key to close this window..." key\n exit 1\nfi'
28
26
  self.success_handling = 'echo "Command completed successfully"\nsleep 2'
29
-
30
- # Load configuration
31
27
  self.config = self._apply_config_template()
32
-
33
- # Ensure these attributes always exist
34
28
  self.upload_url = ''
35
29
  self.log_level = self.config.get('log_level', 'SILENT')
36
30
  self.log_to_file = self.config.get('log_to_file', False)
@@ -40,14 +34,19 @@ class MacOSContextMenuIntegration:
40
34
 
41
35
  logger.debug(f"Upload enabled: {self.upload_enabled}")
42
36
  logger.debug(f"Upload URL: {self.upload_url}")
43
- logger.debug(f"Authentication: {'Basic Authentication' if self.basic_authentication else ('None' if self.none_authentication else ('Client Cert' if self.client_cert_authentication else 'Unknown'))}")
44
-
45
- self._setup_commands()
46
-
37
+ logger.debug(f"Authentication: {'Basic Authentication' if self.basic_authentication else ('None' if self.none_authentication else ('Client Cert' if self.client_cert_authentication else 'Unknown'))}")
38
+ self._setup_commands()
39
+
47
40
  def _build_cmd(self, base_args, file_placeholder='$1', output_to_source=True, use_upload=False, use_artwork=False, use_json=False, use_compare=False, use_info=False, is_recursive=False, is_split=False, is_folder=False, keep_open=False, log_to_file=False):
48
41
  """Dynamically build command strings for quick actions."""
49
42
  exe = self.exe_path
50
43
  cmd = '#!/bin/bash\n\n'
44
+ # Debug output to see what's being passed to the script
45
+ cmd += 'echo "Arguments received: $@"\n'
46
+ cmd += 'echo "Number of arguments: $#"\n'
47
+ cmd += 'if [ $# -gt 0 ]; then\n'
48
+ cmd += ' echo "First argument: $1"\n'
49
+ cmd += 'fi\n\n'
51
50
 
52
51
  # Add a description of what's being executed
53
52
  cmd += 'echo "Running TonieToolbox'
@@ -70,11 +69,117 @@ class MacOSContextMenuIntegration:
70
69
  else:
71
70
  cmd += ' convert'
72
71
  cmd += ' command..."\n\n'
72
+ # Properly handle paths from macOS Services
73
+ if is_folder or is_recursive:
74
+ # Handle multiple arguments and ensure we get a valid folder
75
+ cmd += '# Handle paths from macOS Services\n'
76
+ cmd += '# First, try to get paths from stdin (macOS passes paths this way)\n'
77
+ cmd += 'if [ -p /dev/stdin ]; then\n'
78
+ cmd += ' PATHS=$(cat /dev/stdin)\n'
79
+ cmd += ' echo "Found paths from stdin: $PATHS"\n'
80
+ cmd += 'fi\n\n'
81
+ cmd += '# If no paths from stdin, check command line arguments\n'
82
+ cmd += 'FOLDER_PATH=""\n'
83
+ cmd += 'if [ -z "$PATHS" ]; then\n'
84
+ cmd += ' for arg in "$@"; do\n'
85
+ cmd += ' if [ -d "$arg" ]; then\n'
86
+ cmd += ' FOLDER_PATH="$arg"\n'
87
+ cmd += ' echo "Processing folder from args: $FOLDER_PATH"\n'
88
+ cmd += ' break\n'
89
+ cmd += ' fi\n'
90
+ cmd += ' done\n'
91
+ cmd += 'else\n'
92
+ cmd += ' for path in $PATHS; do\n'
93
+ cmd += ' if [ -d "$path" ]; then\n'
94
+ cmd += ' FOLDER_PATH="$path"\n'
95
+ cmd += ' echo "Processing folder from stdin: $FOLDER_PATH"\n'
96
+ cmd += ' break\n'
97
+ cmd += ' fi\n'
98
+ cmd += ' done\n'
99
+ cmd += 'fi\n\n'
100
+ cmd += 'if [ -z "$FOLDER_PATH" ]; then\n'
101
+ cmd += ' echo "Error: No valid folder path found in arguments or stdin"\n'
102
+ cmd += ' read -p "Press any key to close this window..." key\n'
103
+ cmd += ' exit 1\n'
104
+ cmd += 'fi\n\n'
105
+
106
+ # Use the variable for the command
107
+ file_placeholder='$FOLDER_PATH'
108
+ elif use_compare:
109
+ # For compare operation, we need two file paths
110
+ cmd += '# Compare requires two files\n'
111
+ cmd += 'if [ $# -lt 2 ]; then\n'
112
+ cmd += ' echo "Error: Compare operation requires two files."\n'
113
+ cmd += ' read -p "Press any key to close this window..." key\n'
114
+ cmd += ' exit 1\n'
115
+ cmd += 'fi\n\n'
116
+ else:
117
+ # For regular file operations, handle paths correctly
118
+ cmd += '# Handle file paths correctly - try multiple methods for macOS\n'
119
+ cmd += 'FILE_PATH=""\n'
120
+
121
+ # First, try to get paths from stdin (macOS passes paths this way sometimes)
122
+ cmd += '# Method 1: Try to read from stdin if available\n'
123
+ cmd += 'if [ -p /dev/stdin ]; then\n'
124
+ cmd += ' STDIN_PATHS=$(cat)\n'
125
+ cmd += ' if [ -n "$STDIN_PATHS" ]; then\n'
126
+ cmd += ' for path in $STDIN_PATHS; do\n'
127
+ cmd += ' if [ -f "$path" ]; then\n'
128
+ cmd += ' FILE_PATH="$path"\n'
129
+ cmd += ' echo "Found file path from stdin: $FILE_PATH"\n'
130
+ cmd += ' break\n'
131
+ cmd += ' fi\n'
132
+ cmd += ' done\n'
133
+ cmd += ' fi\n'
134
+ cmd += 'fi\n\n'
135
+
136
+ # Method 2: Try command line arguments
137
+ cmd += '# Method 2: Check command line arguments\n'
138
+ cmd += 'if [ -z "$FILE_PATH" ]; then\n'
139
+ cmd += ' for arg in "$@"; do\n'
140
+ cmd += ' if [ -f "$arg" ]; then\n'
141
+ cmd += ' FILE_PATH="$arg"\n'
142
+ cmd += ' echo "Found file path from arguments: $FILE_PATH"\n'
143
+ cmd += ' break\n'
144
+ cmd += ' fi\n'
145
+ cmd += ' done\n'
146
+ cmd += 'fi\n\n'
147
+
148
+ # Method 3: Try to handle case where path might be in $1
149
+ cmd += '# Method 3: Try first argument directly\n'
150
+ cmd += 'if [ -z "$FILE_PATH" ] && [ -n "$1" ] && [ -f "$1" ]; then\n'
151
+ cmd += ' FILE_PATH="$1"\n'
152
+ cmd += ' echo "Using first argument directly as file path: $FILE_PATH"\n'
153
+ cmd += 'fi\n\n'
154
+
155
+ # Method 4: Parse automator's encoded path format
156
+ cmd += '# Method 4: Try to decode special format macOS might use\n'
157
+ cmd += 'if [ -z "$FILE_PATH" ] && [ -n "$1" ]; then\n'
158
+ cmd += ' # Sometimes macOS passes paths with "file://" prefix\n'
159
+ cmd += ' DECODED_PATH=$(echo "$1" | sed -e "s|^file://||" -e "s|%20| |g")\n'
160
+ cmd += ' if [ -f "$DECODED_PATH" ]; then\n'
161
+ cmd += ' FILE_PATH="$DECODED_PATH"\n'
162
+ cmd += ' echo "Using decoded path: $FILE_PATH"\n'
163
+ cmd += ' fi\n'
164
+ cmd += 'fi\n\n'
165
+
166
+ # Final check
167
+ cmd += 'if [ -z "$FILE_PATH" ]; then\n'
168
+ cmd += ' echo "Error: Could not find a valid file path. Tried:"\n'
169
+ cmd += ' echo "- Reading from stdin"\n'
170
+ cmd += ' echo "- Command arguments: $@"\n'
171
+ cmd += ' echo "- Decoding URL format"\n'
172
+ cmd += ' read -p "Press any key to close this window..." key\n'
173
+ cmd += ' exit 1\n'
174
+ cmd += 'fi\n\n'
175
+
176
+ # Use the variable for the command
177
+ file_placeholder='$FILE_PATH'
73
178
 
74
179
  # Build the actual command
75
180
  cmd_line = f'"{exe}" {base_args}'
76
181
  if log_to_file:
77
- cmd_line += ' --log-file'
182
+ cmd_line += ' --log-file'
78
183
  if is_recursive:
79
184
  cmd_line += ' --recursive'
80
185
  if output_to_source:
@@ -84,7 +189,28 @@ class MacOSContextMenuIntegration:
84
189
  if is_split:
85
190
  cmd_line += ' --split'
86
191
  if use_compare:
87
- cmd_line += ' --compare "$1" "$2"'
192
+ # For compare, we need to handle two files
193
+ cmd += '# Find two TAF files for comparison\n'
194
+ cmd += 'FILE1=""\n'
195
+ cmd += 'FILE2=""\n'
196
+ cmd += 'for arg in "$@"; do\n'
197
+ cmd += ' if [ -f "$arg" ]; then\n'
198
+ cmd += ' if [ -z "$FILE1" ]; then\n'
199
+ cmd += ' FILE1="$arg"\n'
200
+ cmd += ' echo "First TAF file: $FILE1"\n'
201
+ cmd += ' elif [ -z "$FILE2" ]; then\n'
202
+ cmd += ' FILE2="$arg"\n'
203
+ cmd += ' echo "Second TAF file: $FILE2"\n'
204
+ cmd += ' break\n'
205
+ cmd += ' fi\n'
206
+ cmd += ' fi\n'
207
+ cmd += 'done\n\n'
208
+ cmd += 'if [ -z "$FILE1" ] || [ -z "$FILE2" ]; then\n'
209
+ cmd += ' echo "Error: Need two TAF files for comparison."\n'
210
+ cmd += ' read -p "Press any key to close this window..." key\n'
211
+ cmd += ' exit 1\n'
212
+ cmd += 'fi\n\n'
213
+ cmd_line += ' --compare "$FILE1" "$FILE2"'
88
214
  else:
89
215
  cmd_line += f' "{file_placeholder}"'
90
216
  if use_upload:
@@ -101,6 +227,7 @@ class MacOSContextMenuIntegration:
101
227
  cmd_line += ' --create-custom-json'
102
228
 
103
229
  # Add the command to the script
230
+ cmd += f'echo "Executing: {cmd_line}"\n'
104
231
  cmd += f'{cmd_line}\n\n'
105
232
 
106
233
  # Add error and success handling
@@ -146,8 +273,11 @@ class MacOSContextMenuIntegration:
146
273
  self.upload_folder_artwork_json_cmd = self._build_cmd(f'{log_level_arg}', is_recursive=True, is_folder=True, use_upload=True, use_artwork=True, use_json=True, log_to_file=self.log_to_file)
147
274
 
148
275
  def _apply_config_template(self):
149
- """Apply the default configuration template if config.json is missing or invalid."""
276
+ """Apply the default configuration template if config.json is missing or invalid. Extracts the icon from base64 if not present."""
150
277
  config_path = os.path.join(self.output_dir, 'config.json')
278
+ icon_path = os.path.join(self.output_dir, 'icon.ico')
279
+ if not os.path.exists(icon_path):
280
+ base64_to_ico(ICON_BASE64, icon_path)
151
281
  if not os.path.exists(config_path):
152
282
  with open(config_path, 'w') as f:
153
283
  json.dump(CONFIG_TEMPLATE, f, indent=4)
@@ -174,7 +304,6 @@ class MacOSContextMenuIntegration:
174
304
 
175
305
  def _setup_upload(self):
176
306
  """Set up upload functionality based on config.json settings"""
177
- # Always initialize authentication flags
178
307
  self.basic_authentication = False
179
308
  self.client_cert_authentication = False
180
309
  self.none_authentication = False
@@ -210,22 +339,16 @@ class MacOSContextMenuIntegration:
210
339
  return bool(self.upload_url)
211
340
  except Exception as e:
212
341
  logger.debug(f"Unexpected error while loading configuration: {e}")
213
- return False
214
-
342
+ return False
215
343
  def _create_quick_action(self, name, command, file_types=None, directory_based=False):
216
344
  """Create a macOS Quick Action (Service) with the given name and command."""
217
- # Create Quick Action directory
218
345
  action_dir = os.path.join(self.services_dir, f"{name}.workflow")
219
346
  os.makedirs(action_dir, exist_ok=True)
220
-
221
- # Create Contents directory
222
347
  contents_dir = os.path.join(action_dir, "Contents")
223
348
  os.makedirs(contents_dir, exist_ok=True)
224
-
225
- # Create document.wflow file with plist content
226
349
  document_path = os.path.join(contents_dir, "document.wflow")
227
350
 
228
- # Create Info.plist
351
+ # Set up the plist to ensure the service appears in context menus
229
352
  info_plist = {
230
353
  "NSServices": [
231
354
  {
@@ -237,30 +360,27 @@ class MacOSContextMenuIntegration:
237
360
  "NSApplicationIdentifier": "com.apple.finder"
238
361
  },
239
362
  "NSSendFileTypes": file_types if file_types else [],
240
- "NSSendTypes": ["NSFilenamesPboardType"] if directory_based else []
363
+ "NSSendTypes": ["NSFilenamesPboardType"], # Always include this to ensure paths are passed correctly
364
+ "NSUserData": name,
365
+ "NSExecutable": "script", # Ensure macOS knows which script to run
366
+ "NSReturnTypes": []
241
367
  }
242
368
  ]
243
369
  }
244
370
 
245
371
  info_path = os.path.join(contents_dir, "Info.plist")
246
372
  with open(info_path, "wb") as f:
247
- plistlib.dump(info_plist, f)
248
-
249
- # Create script file
373
+ plistlib.dump(info_plist, f)
250
374
  script_dir = os.path.join(contents_dir, "MacOS")
251
375
  os.makedirs(script_dir, exist_ok=True)
252
376
  script_path = os.path.join(script_dir, "script")
253
377
 
254
378
  with open(script_path, "w") as f:
255
- f.write(command)
256
-
257
- # Make the script executable
379
+ f.write(command)
258
380
  os.chmod(script_path, 0o755)
259
-
260
- # Create document.wflow file with a basic workflow definition
261
381
  workflow = {
262
382
  "AMApplication": "Automator",
263
- "AMCanShowSelectedItemsWhenRun": False,
383
+ "AMCanShowSelectedItemsWhenRun": True,
264
384
  "AMCanShowWhenRun": True,
265
385
  "AMDockBadgeLabel": "",
266
386
  "AMDockBadgeStyle": "badge",
@@ -272,7 +392,11 @@ class MacOSContextMenuIntegration:
272
392
  "parameters": {
273
393
  "shell": "/bin/bash",
274
394
  "script": command,
275
- "input": "as arguments"
395
+ "input": "as arguments",
396
+ "showStdout": True,
397
+ "showStderr": True,
398
+ "showOutput": True,
399
+ "runAsAdmin": False
276
400
  }
277
401
  }
278
402
  ],
@@ -283,107 +407,113 @@ class MacOSContextMenuIntegration:
283
407
  },
284
408
  "AMWorkflowSchemeVersion": 2.0,
285
409
  }
286
-
287
410
  with open(document_path, "wb") as f:
288
411
  plistlib.dump(workflow, f)
289
412
 
290
413
  return action_dir
291
-
414
+
415
+ def _extension_to_uti(self, extension):
416
+ """Convert a file extension to macOS UTI (Uniform Type Identifier)."""
417
+ uti_map = UTI_MAPPINGS
418
+ ext = extension.lower().lstrip('.')
419
+ return uti_map.get(ext, f'public.{ext}')
420
+
292
421
  def _generate_audio_extension_actions(self):
293
422
  """Generate Quick Actions for supported audio file extensions."""
294
423
  extensions = [ext.lower().lstrip('.') for ext in SUPPORTED_EXTENSIONS]
295
-
296
- # Create audio file actions
424
+ # Convert extensions to UTIs (Uniform Type Identifiers)
425
+ utis = [self._extension_to_uti(ext) for ext in extensions]
297
426
  self._create_quick_action(
298
427
  "TonieToolbox - Convert to TAF",
299
428
  self.convert_cmd,
300
- file_types=extensions
429
+ file_types=utis
301
430
  )
302
431
 
303
432
  if self.upload_enabled:
304
433
  self._create_quick_action(
305
434
  "TonieToolbox - Convert and Upload",
306
435
  self.upload_cmd,
307
- file_types=extensions
436
+ file_types=utis
308
437
  )
309
438
 
310
439
  self._create_quick_action(
311
440
  "TonieToolbox - Convert, Upload with Artwork",
312
441
  self.upload_artwork_cmd,
313
- file_types=extensions
442
+ file_types=utis
314
443
  )
315
444
 
316
445
  self._create_quick_action(
317
446
  "TonieToolbox - Convert, Upload with Artwork and JSON",
318
447
  self.upload_artwork_json_cmd,
319
- file_types=extensions
448
+ file_types=utis
320
449
  )
321
-
450
+
322
451
  def _generate_taf_file_actions(self):
323
452
  """Generate Quick Actions for .taf files."""
453
+ taf_uti = self._extension_to_uti("taf") # Use UTI for TAF files
454
+
324
455
  self._create_quick_action(
325
456
  "TonieToolbox - Show Info",
326
457
  self.show_info_cmd,
327
- file_types=["taf"]
458
+ file_types=[taf_uti]
328
459
  )
329
460
 
330
461
  self._create_quick_action(
331
462
  "TonieToolbox - Extract Opus Tracks",
332
463
  self.extract_opus_cmd,
333
- file_types=["taf"]
464
+ file_types=[taf_uti]
334
465
  )
335
466
 
336
467
  if self.upload_enabled:
337
468
  self._create_quick_action(
338
469
  "TonieToolbox - Upload",
339
470
  self.upload_taf_cmd,
340
- file_types=["taf"]
471
+ file_types=[taf_uti]
341
472
  )
342
-
343
473
  self._create_quick_action(
344
474
  "TonieToolbox - Upload with Artwork",
345
475
  self.upload_taf_artwork_cmd,
346
- file_types=["taf"]
476
+ file_types=[taf_uti]
347
477
  )
348
478
 
349
479
  self._create_quick_action(
350
480
  "TonieToolbox - Upload with Artwork and JSON",
351
481
  self.upload_taf_artwork_json_cmd,
352
- file_types=["taf"]
482
+ file_types=[taf_uti]
483
+ )
484
+
485
+ self._create_quick_action(
486
+ "TonieToolbox - Compare with another TAF file",
487
+ self.compare_taf_cmd,
488
+ file_types=[taf_uti]
353
489
  )
354
490
 
355
- self._create_quick_action(
356
- "TonieToolbox - Compare with another TAF file",
357
- self.compare_taf_cmd,
358
- file_types=["taf"]
359
- )
360
-
361
491
  def _generate_folder_actions(self):
362
492
  """Generate Quick Actions for folders."""
363
493
  self._create_quick_action(
364
- "TonieToolbox - Convert Folder to TAF (recursive)",
494
+ "TonieToolbox - 1. Convert Folder to TAF (recursive)",
365
495
  self.convert_folder_cmd,
366
496
  directory_based=True
367
497
  )
368
498
 
369
499
  if self.upload_enabled:
370
500
  self._create_quick_action(
371
- "TonieToolbox - Convert Folder and Upload (recursive)",
501
+ "TonieToolbox - 2. Convert Folder and Upload (recursive)",
372
502
  self.upload_folder_cmd,
373
503
  directory_based=True
374
504
  )
375
505
 
376
506
  self._create_quick_action(
377
- "TonieToolbox - Convert Folder, Upload with Artwork (recursive)",
507
+ "TonieToolbox - 3. Convert Folder, Upload with Artwork (recursive)",
378
508
  self.upload_folder_artwork_cmd,
379
509
  directory_based=True
380
510
  )
381
511
 
382
512
  self._create_quick_action(
383
- "TonieToolbox - Convert Folder, Upload with Artwork and JSON (recursive)",
513
+ "TonieToolbox - 4. Convert Folder, Upload with Artwork and JSON (recursive)",
384
514
  self.upload_folder_artwork_json_cmd,
385
515
  directory_based=True
386
- )
516
+ )
387
517
 
388
518
  def install_quick_actions(self):
389
519
  """
@@ -409,15 +539,14 @@ class MacOSContextMenuIntegration:
409
539
  # Refresh the Services menu by restarting the Finder
410
540
  result = subprocess.run(["killall", "-HUP", "Finder"], check=False,
411
541
  capture_output=True, text=True)
412
-
413
- print("TonieToolbox Quick Actions installed successfully.")
414
- print("You'll find them in the Services menu when right-clicking on audio files, TAF files, or folders.")
542
+ logger.info("TonieToolbox Quick Actions installed successfully.")
543
+ logger.info("You'll find them in the Services menu when right-clicking on audio files, TAF files, or folders.")
415
544
 
416
545
  return True
417
546
  except Exception as e:
418
547
  logger.error(f"Failed to install Quick Actions: {e}")
419
548
  return False
420
-
549
+
421
550
  def uninstall_quick_actions(self):
422
551
  """
423
552
  Uninstall all TonieToolbox Quick Actions.
@@ -444,7 +573,9 @@ class MacOSContextMenuIntegration:
444
573
  return not any_failures
445
574
  except Exception as e:
446
575
  logger.error(f"Failed to uninstall Quick Actions: {e}")
447
- return False @classmethod
576
+ return False
577
+
578
+ @classmethod
448
579
  def install(cls):
449
580
  """
450
581
  Generate Quick Actions and install them.
@@ -2,7 +2,8 @@
2
2
  import os
3
3
  import sys
4
4
  import json
5
- from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE
5
+ from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE, ICON_BASE64
6
+ from .artwork import base64_to_ico
6
7
  from .logger import get_logger
7
8
 
8
9
  logger = get_logger('integration_windows')
@@ -127,8 +128,11 @@ class WindowsClassicContextMenuIntegration:
127
128
  self.upload_folder_artwork_json_cmd = self._build_cmd(f'{log_level_arg}', is_recursive=True, is_folder=True, use_upload=True, use_artwork=True, use_json=True, log_to_file=self.log_to_file)
128
129
 
129
130
  def _apply_config_template(self):
130
- """Apply the default configuration template if config.json is missing or invalid."""
131
+ """Apply the default configuration template if config.json is missing or invalid. Extracts the icon from base64 if not present."""
131
132
  config_path = os.path.join(self.output_dir, 'config.json')
133
+ icon_path = os.path.join(self.output_dir, 'icon.ico')
134
+ if not os.path.exists(icon_path):
135
+ base64_to_ico(ICON_BASE64, icon_path)
132
136
  if not os.path.exists(config_path):
133
137
  with open(config_path, 'w') as f:
134
138
  json.dump(CONFIG_TEMPLATE, f, indent=4)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TonieToolbox
3
- Version: 0.6.0a2
4
- Summary: Create files for the Tonie box and interact with TeddyCloud servers
3
+ Version: 0.6.0a4
4
+ Summary: Convert audio files to Toniebox compatible format (.TAF) and interact with TeddyCloud.
5
5
  Home-page: https://github.com/Quentendo64/TonieToolbox
6
6
  Author: Quentendo64
7
7
  Author-email: Quentendo64 <quentin@wohlfeil.at>
@@ -23,6 +23,7 @@ Requires-Dist: protobuf<=3.19.0
23
23
  Requires-Dist: requests>=2.32.3
24
24
  Requires-Dist: mutagen>=1.47.0
25
25
  Requires-Dist: packaging>=25.0
26
+ Requires-Dist: tqdm>=4.67.1
26
27
  Provides-Extra: test
27
28
  Requires-Dist: pytest>=8.3.5; extra == "test"
28
29
  Requires-Dist: pytest-cov>=6.1.1; extra == "test"
@@ -806,3 +807,6 @@ If you need help, have questions, or want to report a bug, please use the follow
806
807
  - [GitHub Issues](https://github.com/Quentendo64/TonieToolbox/issues) for bug reports and feature requests
807
808
  - [GitHub Discussions](https://github.com/Quentendo64/TonieToolbox/discussions) for general questions and community support
808
809
  - [HOWTO Guide](HOWTO.md) for common usage instructions
810
+
811
+ ## Attribution
812
+ [Parrot Icon created by Freepik - Flaticon](https://www.flaticon.com/free-animated-icons/parrot)
@@ -1,14 +1,14 @@
1
- TonieToolbox/__init__.py,sha256=SvYXuFZfiIhKR8yAYwmNjGV3NhgQhEuVftssbgMvxwg,98
2
- TonieToolbox/__main__.py,sha256=pD-goy-ke-M3Z8zkbUgW1IF94UQPGQSHql15yeBBDzk,34040
3
- TonieToolbox/artwork.py,sha256=fOlYx1cffVq-2u1e_qiW5bd3LpPCGMmIfZAxIwC05tA,4451
1
+ TonieToolbox/__init__.py,sha256=P-i-pmjFHddy0r76UYtLh4dFA2jppC0wc_BqhDAzfqw,98
2
+ TonieToolbox/__main__.py,sha256=F_FHZC7rLejBdEQ4plOg6dcyV4lgFKZDvJtQHpCthKs,34934
3
+ TonieToolbox/artwork.py,sha256=VRDa9Ydeq7AsXhRKYyEqpfFNH64AA1Xek7yo60bn8OI,5606
4
4
  TonieToolbox/audio_conversion.py,sha256=0GpC6mSRYikIjf_A1w26LAnYtCP2gpHLEKozOISapnM,17190
5
- TonieToolbox/constants.py,sha256=_fLMCz8jz6XBgpT11oy4PRLDoKkr_dRQMXRo3aqPOmo,7510
6
- TonieToolbox/dependency_manager.py,sha256=EvVUO4T1CrhUXlrVk9HBgCRDER3b1BRNdgkZLSpCTho,27921
5
+ TonieToolbox/constants.py,sha256=DabAgzKeG8trpV9I6tie1FA6mt3BhTRf_gF5UwtMpE4,33970
6
+ TonieToolbox/dependency_manager.py,sha256=7HCyUhVLZ6l0W1HPdYr3AgLc935S43qdTLpf1PipPkQ,49425
7
7
  TonieToolbox/filename_generator.py,sha256=ATCG4w8uN1vyAqvmdhOtpJLlb9QFKCnYIdBViYqpHjw,3464
8
- TonieToolbox/integration.py,sha256=NEQpKQSwLa6el7DoIqWbscBUGmRrYls_UiSmmvpSpxw,2785
9
- TonieToolbox/integration_macos.py,sha256=Zrt21X0sjtCG1fGnFX5N4f0zKVt8y_B4_F9YFZjmtko,20072
8
+ TonieToolbox/integration.py,sha256=TXCkXxmeMGtw8G8M-jUVuKa7i_hI0JvVoVlIvYFvEnc,3097
9
+ TonieToolbox/integration_macos.py,sha256=HWHBcMU5BRe50ak2nqB9kIFJS83sJ8t2_B_0FMhat2U,27159
10
10
  TonieToolbox/integration_ubuntu.py,sha256=MU6W0xRCdoHBxrIiOIHePqYTF5Wvn4JxBnDQUPf6fgg,33
11
- TonieToolbox/integration_windows.py,sha256=SSVg-9bf8wDQMuJgg-j_6cUczcx7H1-C1mbEIlNJlzs,23691
11
+ TonieToolbox/integration_windows.py,sha256=7F_8Dh7fWHuvCfcigM5TB-bF5CupzM6iQ-YqOvvNVFQ,23939
12
12
  TonieToolbox/logger.py,sha256=Q_cXbCWfzNmt5q6fvVzeM8IugkD24CSZAVjuf16n6b4,3120
13
13
  TonieToolbox/media_tags.py,sha256=oDlLe0AyvmIdQlqPzH74AUCqwbZZ-49AQKAJdrW26XE,20830
14
14
  TonieToolbox/ogg_page.py,sha256=IHdP0er0TYjyLfON8zes11FdQtRab3QNxeK6sxnAX08,22340
@@ -22,9 +22,9 @@ TonieToolbox/tonie_header.proto,sha256=WaWfwO4VrwGtscK2ujfDRKtpeBpaVPoZhI8iMmR-C
22
22
  TonieToolbox/tonie_header_pb2.py,sha256=s5bp4ULTEekgq6T61z9fDkRavyPM-3eREs20f_Pxxe8,3665
23
23
  TonieToolbox/tonies_json.py,sha256=YGS2wtaDudxxSy7QuRLWaE5n4bf_AyoSvVLH1Vdh8SE,60754
24
24
  TonieToolbox/version_handler.py,sha256=MLpJ9mSEHkcSoyePnACpfINHTSB1q1_4iEgcT1tGqNU,10028
25
- tonietoolbox-0.6.0a2.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
26
- tonietoolbox-0.6.0a2.dist-info/METADATA,sha256=RAyhO4jFdnZ42n8HSPw6vBDMj1YcY1F-X1V32davNmo,26849
27
- tonietoolbox-0.6.0a2.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
28
- tonietoolbox-0.6.0a2.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
29
- tonietoolbox-0.6.0a2.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
30
- tonietoolbox-0.6.0a2.dist-info/RECORD,,
25
+ tonietoolbox-0.6.0a4.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
26
+ tonietoolbox-0.6.0a4.dist-info/METADATA,sha256=1ygRy4_HXQsn3C_TcLydyvkdpTppmYECp4OH7eQ2NTE,27009
27
+ tonietoolbox-0.6.0a4.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
28
+ tonietoolbox-0.6.0a4.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
29
+ tonietoolbox-0.6.0a4.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
30
+ tonietoolbox-0.6.0a4.dist-info/RECORD,,