TonieToolbox 0.6.0a1__tar.gz → 0.6.0a2__tar.gz
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-0.6.0a1/TonieToolbox.egg-info → tonietoolbox-0.6.0a2}/PKG-INFO +2 -2
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/README.md +1 -1
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/__init__.py +1 -1
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/__main__.py +8 -2
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/constants.py +17 -0
- tonietoolbox-0.6.0a2/TonieToolbox/integration.py +68 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/integration_macos.py +89 -40
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/integration_windows.py +47 -14
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2/TonieToolbox.egg-info}/PKG-INFO +2 -2
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox.egg-info/SOURCES.txt +0 -1
- tonietoolbox-0.6.0a1/TonieToolbox/config.py +0 -1
- tonietoolbox-0.6.0a1/TonieToolbox/integration.py +0 -20
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/LICENSE.md +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/MANIFEST.in +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/artwork.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/audio_conversion.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/dependency_manager.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/filename_generator.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/integration_ubuntu.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/logger.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/media_tags.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/ogg_page.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/opus_packet.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/recursive_processor.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tags.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/teddycloud.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tonie_analysis.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tonie_file.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tonie_header.proto +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tonie_header_pb2.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/tonies_json.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox/version_handler.py +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox.egg-info/dependency_links.txt +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox.egg-info/entry_points.txt +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox.egg-info/requires.txt +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/TonieToolbox.egg-info/top_level.txt +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/pyproject.toml +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/setup.cfg +0 -0
- {tonietoolbox-0.6.0a1 → tonietoolbox-0.6.0a2}/setup.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: TonieToolbox
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.0a2
|
4
4
|
Summary: Create files for the Tonie box and interact with TeddyCloud servers
|
5
5
|
Home-page: https://github.com/Quentendo64/TonieToolbox
|
6
6
|
Author: Quentendo64
|
@@ -225,7 +225,7 @@ docker run --rm -v "$(pwd)/input:/tonietoolbox/input" -v "$(pwd)/output:/tonieto
|
|
225
225
|
docker run --rm -v "%cd%\input:/tonietoolbox/input" -v "%cd%\output:/tonietoolbox/output" quentendo64/tonietoolbox input/my-audio-file.mp3
|
226
226
|
```
|
227
227
|
|
228
|
-
**Or using docker-compose
|
228
|
+
**Or using docker-compose:**
|
229
229
|
|
230
230
|
```shell
|
231
231
|
docker-compose run --rm tonietoolbox input/my-audio-file.mp3
|
@@ -192,7 +192,7 @@ docker run --rm -v "$(pwd)/input:/tonietoolbox/input" -v "$(pwd)/output:/tonieto
|
|
192
192
|
docker run --rm -v "%cd%\input:/tonietoolbox/input" -v "%cd%\output:/tonietoolbox/output" quentendo64/tonietoolbox input/my-audio-file.mp3
|
193
193
|
```
|
194
194
|
|
195
|
-
**Or using docker-compose
|
195
|
+
**Or using docker-compose:**
|
196
196
|
|
197
197
|
```shell
|
198
198
|
docker-compose run --rm tonietoolbox input/my-audio-file.mp3
|
@@ -21,7 +21,7 @@ from .teddycloud import TeddyCloudClient
|
|
21
21
|
from .tags import get_tags
|
22
22
|
from .tonies_json import fetch_and_update_tonies_json_v1, fetch_and_update_tonies_json_v2
|
23
23
|
from .artwork import upload_artwork
|
24
|
-
from .integration import handle_integration
|
24
|
+
from .integration import handle_integration, handle_config
|
25
25
|
|
26
26
|
def main():
|
27
27
|
"""Entry point for the TonieToolbox application."""
|
@@ -101,6 +101,8 @@ def main():
|
|
101
101
|
parser.add_argument('-D', '--detailed-compare', action='store_true',
|
102
102
|
help='Show detailed OGG page differences when comparing files')
|
103
103
|
# ------------- Parser - Context Menu Integration -------------
|
104
|
+
parser.add_argument('--config-integration', action='store_true',
|
105
|
+
help='Configure context menu integration')
|
104
106
|
parser.add_argument('--install-integration', action='store_true',
|
105
107
|
help='Integrate with the system (e.g., create context menu entries)')
|
106
108
|
parser.add_argument('--uninstall-integration', action='store_true',
|
@@ -133,7 +135,7 @@ def main():
|
|
133
135
|
args = parser.parse_args()
|
134
136
|
|
135
137
|
# ------------- Parser - Source Input -------------
|
136
|
-
if args.input_filename is None and not (args.get_tags or args.upload or args.install_integration or args.uninstall_integration):
|
138
|
+
if args.input_filename is None and not (args.get_tags or args.upload or args.install_integration or args.uninstall_integration or args.config_integration):
|
137
139
|
parser.error("the following arguments are required: SOURCE")
|
138
140
|
|
139
141
|
# ------------- Logging -------------
|
@@ -185,6 +187,10 @@ def main():
|
|
185
187
|
else:
|
186
188
|
logger.error("Failed to handle context menu integration")
|
187
189
|
sys.exit(0)
|
190
|
+
if args.config_integration:
|
191
|
+
logger.debug("Opening configuration file for editing")
|
192
|
+
handle_config()
|
193
|
+
sys.exit(0)
|
188
194
|
# ------------- Normalize Path Input -------------
|
189
195
|
if args.input_filename:
|
190
196
|
logger.debug("Original input path: %s", args.input_filename)
|
@@ -171,4 +171,21 @@ TAG_MAPPINGS = {
|
|
171
171
|
'albuminterpret': 'albumartist', # German tag name
|
172
172
|
'interpret': 'artist', # German tag name
|
173
173
|
|
174
|
+
}
|
175
|
+
|
176
|
+
CONFIG_TEMPLATE = {
|
177
|
+
"metadata": {
|
178
|
+
"description": "TonieToolbox configuration",
|
179
|
+
"config_version": "1.0"
|
180
|
+
},
|
181
|
+
"log_level": "silent", # Options: trace, debug, info, warning, error, critical, silent
|
182
|
+
"log_to_file": False, # True if you want to log to a file ~\.tonietoolbox\logs
|
183
|
+
"upload": {
|
184
|
+
"url": [""], # https://teddycloud.example.com
|
185
|
+
"ignore_ssl_verify": False, # True if you want to ignore SSL certificate verification
|
186
|
+
"username": "", # Basic Auth username
|
187
|
+
"password": "", # Basic Auth password
|
188
|
+
"client_cert_path": "", # Path to client certificate file
|
189
|
+
"client_cert_key_path": "" # Path to client certificate key file
|
190
|
+
}
|
174
191
|
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import platform
|
2
|
+
from .logger import get_logger
|
3
|
+
|
4
|
+
logger = get_logger(__name__)
|
5
|
+
|
6
|
+
def handle_integration(args):
|
7
|
+
import platform
|
8
|
+
if platform.system() == 'Windows':
|
9
|
+
from .integration_windows import WindowsClassicContextMenuIntegration as ContextMenuIntegration
|
10
|
+
if args.install_integration:
|
11
|
+
success = ContextMenuIntegration.install()
|
12
|
+
if success:
|
13
|
+
logger.info("Integration installed successfully.")
|
14
|
+
return True
|
15
|
+
else:
|
16
|
+
logger.error("Integration installation failed.")
|
17
|
+
return False
|
18
|
+
elif args.uninstall_integration:
|
19
|
+
success = ContextMenuIntegration.uninstall()
|
20
|
+
if success:
|
21
|
+
logger.info("Integration uninstalled successfully.")
|
22
|
+
return True
|
23
|
+
else:
|
24
|
+
logger.error("Integration uninstallation failed.")
|
25
|
+
return False
|
26
|
+
elif platform.system() == 'Darwin':
|
27
|
+
from .integration_macos import MacOSContextMenuIntegration as ContextMenuIntegration
|
28
|
+
if args.install_integration:
|
29
|
+
success = ContextMenuIntegration.install()
|
30
|
+
if success:
|
31
|
+
logger.info("Integration installed successfully.")
|
32
|
+
return True
|
33
|
+
else:
|
34
|
+
logger.error("Integration installation failed.")
|
35
|
+
return False
|
36
|
+
elif args.uninstall_integration:
|
37
|
+
success = ContextMenuIntegration.uninstall()
|
38
|
+
if success:
|
39
|
+
logger.info("Integration uninstalled successfully.")
|
40
|
+
return True
|
41
|
+
else:
|
42
|
+
logger.error("Integration uninstallation failed.")
|
43
|
+
return False
|
44
|
+
elif platform.system() == 'Linux':
|
45
|
+
raise NotImplementedError("Context menu integration is not supported on Linux YET. But Soon™")
|
46
|
+
else:
|
47
|
+
raise NotImplementedError(f"Context menu integration is not supported on this OS: {platform.system()}")
|
48
|
+
|
49
|
+
def handle_config():
|
50
|
+
"""Opens the configuration file in the default text editor."""
|
51
|
+
import os
|
52
|
+
import platform
|
53
|
+
import subprocess
|
54
|
+
|
55
|
+
config_path = os.path.join(os.path.expanduser("~"), ".tonietoolbox", "config.json")
|
56
|
+
|
57
|
+
if not os.path.exists(config_path):
|
58
|
+
logger.info(f"Configuration file not found at {config_path}.")
|
59
|
+
logger.info("Creating a new configuration file. Using --install-integration will create a new config file.")
|
60
|
+
return
|
61
|
+
if platform.system() == "Windows":
|
62
|
+
os.startfile(config_path)
|
63
|
+
elif platform.system() == "Darwin":
|
64
|
+
subprocess.call(["open", config_path])
|
65
|
+
elif platform.system() == "Linux":
|
66
|
+
subprocess.call(["xdg-open", config_path])
|
67
|
+
else:
|
68
|
+
logger.error(f"Unsupported OS: {platform.system()}")
|
@@ -5,7 +5,7 @@ import json
|
|
5
5
|
import plistlib
|
6
6
|
import subprocess
|
7
7
|
from pathlib import Path
|
8
|
-
from .constants import SUPPORTED_EXTENSIONS
|
8
|
+
from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE
|
9
9
|
from .logger import get_logger
|
10
10
|
|
11
11
|
logger = get_logger('integration_macos')
|
@@ -28,7 +28,7 @@ class MacOSContextMenuIntegration:
|
|
28
28
|
self.success_handling = 'echo "Command completed successfully"\nsleep 2'
|
29
29
|
|
30
30
|
# Load configuration
|
31
|
-
self.config = self.
|
31
|
+
self.config = self._apply_config_template()
|
32
32
|
|
33
33
|
# Ensure these attributes always exist
|
34
34
|
self.upload_url = ''
|
@@ -145,6 +145,18 @@ class MacOSContextMenuIntegration:
|
|
145
145
|
self.upload_folder_artwork_cmd = self._build_cmd(f'{log_level_arg}', is_recursive=True, is_folder=True, use_upload=True, use_artwork=True, log_to_file=self.log_to_file)
|
146
146
|
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
147
|
|
148
|
+
def _apply_config_template(self):
|
149
|
+
"""Apply the default configuration template if config.json is missing or invalid."""
|
150
|
+
config_path = os.path.join(self.output_dir, 'config.json')
|
151
|
+
if not os.path.exists(config_path):
|
152
|
+
with open(config_path, 'w') as f:
|
153
|
+
json.dump(CONFIG_TEMPLATE, f, indent=4)
|
154
|
+
logger.debug(f"Default configuration created at {config_path}")
|
155
|
+
return CONFIG_TEMPLATE
|
156
|
+
else:
|
157
|
+
logger.debug(f"Configuration file found at {config_path}")
|
158
|
+
return self._load_config()
|
159
|
+
|
148
160
|
def _load_config(self):
|
149
161
|
"""Load configuration settings from config.json"""
|
150
162
|
config_path = os.path.join(self.output_dir, 'config.json')
|
@@ -371,58 +383,95 @@ class MacOSContextMenuIntegration:
|
|
371
383
|
"TonieToolbox - Convert Folder, Upload with Artwork and JSON (recursive)",
|
372
384
|
self.upload_folder_artwork_json_cmd,
|
373
385
|
directory_based=True
|
374
|
-
)
|
375
|
-
|
386
|
+
)
|
387
|
+
|
376
388
|
def install_quick_actions(self):
|
377
|
-
"""
|
378
|
-
|
379
|
-
os.makedirs(self.services_dir, exist_ok=True)
|
380
|
-
|
381
|
-
# Check if the icon exists, copy default if needed
|
382
|
-
if not os.path.exists(self.icon_path):
|
383
|
-
# Include code to extract icon from resources
|
384
|
-
logger.debug(f"Icon not found at {self.icon_path}, using default")
|
385
|
-
|
386
|
-
# Generate Quick Actions for different file types
|
387
|
-
self._generate_audio_extension_actions()
|
388
|
-
self._generate_taf_file_actions()
|
389
|
-
self._generate_folder_actions()
|
390
|
-
|
391
|
-
# Refresh the Services menu by restarting the Finder
|
392
|
-
subprocess.run(["killall", "-HUP", "Finder"], check=False)
|
389
|
+
"""
|
390
|
+
Install all Quick Actions.
|
393
391
|
|
394
|
-
|
395
|
-
|
392
|
+
Returns:
|
393
|
+
bool: True if all actions were installed successfully, False otherwise.
|
394
|
+
"""
|
395
|
+
try:
|
396
|
+
# Ensure Services directory exists
|
397
|
+
os.makedirs(self.services_dir, exist_ok=True)
|
398
|
+
|
399
|
+
# Check if the icon exists, copy default if needed
|
400
|
+
if not os.path.exists(self.icon_path):
|
401
|
+
# Include code to extract icon from resources
|
402
|
+
logger.debug(f"Icon not found at {self.icon_path}, using default")
|
403
|
+
|
404
|
+
# Generate Quick Actions for different file types
|
405
|
+
self._generate_audio_extension_actions()
|
406
|
+
self._generate_taf_file_actions()
|
407
|
+
self._generate_folder_actions()
|
408
|
+
|
409
|
+
# Refresh the Services menu by restarting the Finder
|
410
|
+
result = subprocess.run(["killall", "-HUP", "Finder"], check=False,
|
411
|
+
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.")
|
415
|
+
|
416
|
+
return True
|
417
|
+
except Exception as e:
|
418
|
+
logger.error(f"Failed to install Quick Actions: {e}")
|
419
|
+
return False
|
396
420
|
|
397
421
|
def uninstall_quick_actions(self):
|
398
|
-
"""
|
399
|
-
|
400
|
-
for item in os.listdir(self.services_dir):
|
401
|
-
if item.startswith("TonieToolbox - ") and item.endswith(".workflow"):
|
402
|
-
action_path = os.path.join(self.services_dir, item)
|
403
|
-
try:
|
404
|
-
subprocess.run(["rm", "-rf", action_path], check=True)
|
405
|
-
print(f"Removed: {item}")
|
406
|
-
except subprocess.CalledProcessError:
|
407
|
-
print(f"Failed to remove: {item}")
|
408
|
-
|
409
|
-
# Refresh the Services menu
|
410
|
-
subprocess.run(["killall", "-HUP", "Finder"], check=False)
|
422
|
+
"""
|
423
|
+
Uninstall all TonieToolbox Quick Actions.
|
411
424
|
|
412
|
-
|
413
|
-
|
414
|
-
|
425
|
+
Returns:
|
426
|
+
bool: True if all actions were uninstalled successfully, False otherwise.
|
427
|
+
"""
|
428
|
+
try:
|
429
|
+
any_failures = False
|
430
|
+
for item in os.listdir(self.services_dir):
|
431
|
+
if item.startswith("TonieToolbox - ") and item.endswith(".workflow"):
|
432
|
+
action_path = os.path.join(self.services_dir, item)
|
433
|
+
try:
|
434
|
+
subprocess.run(["rm", "-rf", action_path], check=True)
|
435
|
+
print(f"Removed: {item}")
|
436
|
+
except subprocess.CalledProcessError as e:
|
437
|
+
print(f"Failed to remove: {item}")
|
438
|
+
logger.error(f"Error removing {item}: {e}")
|
439
|
+
any_failures = True
|
440
|
+
subprocess.run(["killall", "-HUP", "Finder"], check=False)
|
441
|
+
|
442
|
+
print("TonieToolbox Quick Actions uninstalled successfully.")
|
443
|
+
|
444
|
+
return not any_failures
|
445
|
+
except Exception as e:
|
446
|
+
logger.error(f"Failed to uninstall Quick Actions: {e}")
|
447
|
+
return False @classmethod
|
415
448
|
def install(cls):
|
416
449
|
"""
|
417
450
|
Generate Quick Actions and install them.
|
451
|
+
|
452
|
+
Returns:
|
453
|
+
bool: True if installation was successful, False otherwise.
|
418
454
|
"""
|
419
455
|
instance = cls()
|
420
|
-
instance.install_quick_actions()
|
456
|
+
if instance.install_quick_actions():
|
457
|
+
logger.info("macOS integration installed successfully.")
|
458
|
+
return True
|
459
|
+
else:
|
460
|
+
logger.error("macOS integration installation failed.")
|
461
|
+
return False
|
421
462
|
|
422
463
|
@classmethod
|
423
464
|
def uninstall(cls):
|
424
465
|
"""
|
425
466
|
Uninstall all TonieToolbox Quick Actions.
|
467
|
+
|
468
|
+
Returns:
|
469
|
+
bool: True if uninstallation was successful, False otherwise.
|
426
470
|
"""
|
427
471
|
instance = cls()
|
428
|
-
instance.uninstall_quick_actions()
|
472
|
+
if instance.uninstall_quick_actions():
|
473
|
+
logger.info("macOS integration uninstalled successfully.")
|
474
|
+
return True
|
475
|
+
else:
|
476
|
+
logger.error("macOS integration uninstallation failed.")
|
477
|
+
return False
|
@@ -2,7 +2,7 @@
|
|
2
2
|
import os
|
3
3
|
import sys
|
4
4
|
import json
|
5
|
-
from .constants import SUPPORTED_EXTENSIONS
|
5
|
+
from .constants import SUPPORTED_EXTENSIONS, CONFIG_TEMPLATE
|
6
6
|
from .logger import get_logger
|
7
7
|
|
8
8
|
logger = get_logger('integration_windows')
|
@@ -24,8 +24,7 @@ class WindowsClassicContextMenuIntegration:
|
|
24
24
|
self.separator_above = '"CommandFlags"=dword:00000020'
|
25
25
|
self.error_handling = r' && if %ERRORLEVEL% neq 0 (echo Error: Command failed with error code %ERRORLEVEL% && pause && exit /b %ERRORLEVEL%) else (echo Command completed successfully && ping -n 2 127.0.0.1 > nul)'
|
26
26
|
self.show_info_error_handling = r' && if %ERRORLEVEL% neq 0 (echo Error: Command failed with error code %ERRORLEVEL% && pause && exit /b %ERRORLEVEL%) else (echo. && echo Press any key to close this window... && pause > nul)'
|
27
|
-
self.config = self.
|
28
|
-
# Ensure these attributes always exist
|
27
|
+
self.config = self._apply_config_template()
|
29
28
|
self.upload_url = ''
|
30
29
|
self.log_level = self.config.get('log_level', 'SILENT')
|
31
30
|
self.log_to_file = self.config.get('log_to_file', False)
|
@@ -127,6 +126,18 @@ class WindowsClassicContextMenuIntegration:
|
|
127
126
|
self.upload_folder_artwork_cmd = self._build_cmd(f'{log_level_arg}', is_recursive=True, is_folder=True, use_upload=True, use_artwork=True, log_to_file=self.log_to_file)
|
128
127
|
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)
|
129
128
|
|
129
|
+
def _apply_config_template(self):
|
130
|
+
"""Apply the default configuration template if config.json is missing or invalid."""
|
131
|
+
config_path = os.path.join(self.output_dir, 'config.json')
|
132
|
+
if not os.path.exists(config_path):
|
133
|
+
with open(config_path, 'w') as f:
|
134
|
+
json.dump(CONFIG_TEMPLATE, f, indent=4)
|
135
|
+
logger.debug(f"Default configuration created at {config_path}")
|
136
|
+
return CONFIG_TEMPLATE
|
137
|
+
else:
|
138
|
+
logger.debug(f"Configuration file found at {config_path}")
|
139
|
+
return self._load_config()
|
140
|
+
|
130
141
|
def _load_config(self):
|
131
142
|
"""Load configuration settings from config.json"""
|
132
143
|
config_path = os.path.join(self.output_dir, 'config.json')
|
@@ -360,11 +371,14 @@ class WindowsClassicContextMenuIntegration:
|
|
360
371
|
f.write('\n'.join(unreg_lines))
|
361
372
|
|
362
373
|
return reg_path
|
363
|
-
|
374
|
+
|
364
375
|
def install_registry_files(self, uninstall=False):
|
365
376
|
"""
|
366
377
|
Import the generated .reg file into the Windows registry with UAC elevation.
|
367
378
|
If uninstall is True, imports the uninstaller .reg file.
|
379
|
+
|
380
|
+
Returns:
|
381
|
+
bool: True if registry import was successful, False otherwise.
|
368
382
|
"""
|
369
383
|
import subprocess
|
370
384
|
reg_file = os.path.join(
|
@@ -372,18 +386,27 @@ class WindowsClassicContextMenuIntegration:
|
|
372
386
|
'remove_tonietoolbox_context.reg' if uninstall else 'tonietoolbox_context.reg'
|
373
387
|
)
|
374
388
|
if not os.path.exists(reg_file):
|
375
|
-
|
389
|
+
logger.error(f"Registry file not found: {reg_file}")
|
390
|
+
return False
|
376
391
|
|
377
|
-
# Use PowerShell to run reg.exe import as administrator (fix argument passing)
|
378
392
|
ps_command = (
|
379
|
-
f"Start-Process reg.exe -ArgumentList @('import', '{reg_file}') -Verb RunAs"
|
393
|
+
f"Start-Process reg.exe -ArgumentList @('import', '{reg_file}') -Verb RunAs -Wait -PassThru"
|
380
394
|
)
|
381
395
|
try:
|
382
|
-
subprocess.run(["powershell.exe", "-Command", ps_command], check=
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
396
|
+
result = subprocess.run(["powershell.exe", "-Command", ps_command], check=False,
|
397
|
+
capture_output=True, text=True)
|
398
|
+
|
399
|
+
if result.returncode == 0:
|
400
|
+
logger.info(f"{'Uninstallation' if uninstall else 'Installation'} registry import completed.")
|
401
|
+
return True
|
402
|
+
else:
|
403
|
+
logger.error(f"Registry import command failed with return code {result.returncode}")
|
404
|
+
logger.error(f"STDERR: {result.stderr}")
|
405
|
+
return False
|
406
|
+
|
407
|
+
except subprocess.SubprocessError as e:
|
408
|
+
logger.error(f"Failed to import registry file: {e}")
|
409
|
+
return False
|
387
410
|
|
388
411
|
@classmethod
|
389
412
|
def install(cls):
|
@@ -392,7 +415,12 @@ class WindowsClassicContextMenuIntegration:
|
|
392
415
|
"""
|
393
416
|
instance = cls()
|
394
417
|
instance.generate_registry_files()
|
395
|
-
instance.install_registry_files(uninstall=False)
|
418
|
+
if instance.install_registry_files(uninstall=False):
|
419
|
+
logger.info("Integration installed successfully.")
|
420
|
+
return True
|
421
|
+
else:
|
422
|
+
logger.error("Integration installation failed.")
|
423
|
+
return False
|
396
424
|
|
397
425
|
@classmethod
|
398
426
|
def uninstall(cls):
|
@@ -401,4 +429,9 @@ class WindowsClassicContextMenuIntegration:
|
|
401
429
|
"""
|
402
430
|
instance = cls()
|
403
431
|
instance.generate_registry_files()
|
404
|
-
instance.install_registry_files(uninstall=True)
|
432
|
+
if instance.install_registry_files(uninstall=True):
|
433
|
+
logger.info("Integration uninstalled successfully.")
|
434
|
+
return True
|
435
|
+
else:
|
436
|
+
logger.error("Integration uninstallation failed.")
|
437
|
+
return False
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: TonieToolbox
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.0a2
|
4
4
|
Summary: Create files for the Tonie box and interact with TeddyCloud servers
|
5
5
|
Home-page: https://github.com/Quentendo64/TonieToolbox
|
6
6
|
Author: Quentendo64
|
@@ -225,7 +225,7 @@ docker run --rm -v "$(pwd)/input:/tonietoolbox/input" -v "$(pwd)/output:/tonieto
|
|
225
225
|
docker run --rm -v "%cd%\input:/tonietoolbox/input" -v "%cd%\output:/tonietoolbox/output" quentendo64/tonietoolbox input/my-audio-file.mp3
|
226
226
|
```
|
227
227
|
|
228
|
-
**Or using docker-compose
|
228
|
+
**Or using docker-compose:**
|
229
229
|
|
230
230
|
```shell
|
231
231
|
docker-compose run --rm tonietoolbox input/my-audio-file.mp3
|
@@ -1 +0,0 @@
|
|
1
|
-
## TODO: Add config.py
|
@@ -1,20 +0,0 @@
|
|
1
|
-
import platform
|
2
|
-
|
3
|
-
def handle_integration(args):
|
4
|
-
import platform
|
5
|
-
if platform.system() == 'Windows':
|
6
|
-
from .integration_windows import WindowsClassicContextMenuIntegration as ContextMenuIntegration
|
7
|
-
if args.install_integration:
|
8
|
-
ContextMenuIntegration.install()
|
9
|
-
elif args.uninstall_integration:
|
10
|
-
ContextMenuIntegration.uninstall()
|
11
|
-
elif platform.system() == 'Darwin':
|
12
|
-
from .integration_macos import MacOSContextMenuIntegration as ContextMenuIntegration
|
13
|
-
if args.install_integration:
|
14
|
-
ContextMenuIntegration.install()
|
15
|
-
elif args.uninstall_integration:
|
16
|
-
ContextMenuIntegration.uninstall()
|
17
|
-
elif platform.system() == 'Linux':
|
18
|
-
raise NotImplementedError("Context menu integration is not supported on Linux YET. But Soon™")
|
19
|
-
else:
|
20
|
-
raise NotImplementedError(f"Context menu integration is not supported on this OS: {platform.system()}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|