TonieToolbox 0.5.0a1__py3-none-any.whl → 0.6.0a1__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 +1 -1
- TonieToolbox/__main__.py +148 -127
- TonieToolbox/artwork.py +12 -7
- TonieToolbox/audio_conversion.py +104 -33
- TonieToolbox/config.py +1 -0
- TonieToolbox/constants.py +93 -9
- TonieToolbox/filename_generator.py +6 -8
- TonieToolbox/integration.py +20 -0
- TonieToolbox/integration_macos.py +428 -0
- TonieToolbox/integration_ubuntu.py +1 -0
- TonieToolbox/integration_windows.py +404 -0
- TonieToolbox/logger.py +8 -10
- TonieToolbox/media_tags.py +22 -101
- TonieToolbox/ogg_page.py +39 -39
- TonieToolbox/opus_packet.py +13 -13
- TonieToolbox/recursive_processor.py +32 -33
- TonieToolbox/tags.py +3 -4
- TonieToolbox/teddycloud.py +50 -50
- TonieToolbox/tonie_analysis.py +24 -23
- TonieToolbox/tonie_file.py +86 -71
- TonieToolbox/tonies_json.py +828 -36
- TonieToolbox/version_handler.py +12 -15
- {tonietoolbox-0.5.0a1.dist-info → tonietoolbox-0.6.0a1.dist-info}/METADATA +141 -98
- tonietoolbox-0.6.0a1.dist-info/RECORD +31 -0
- {tonietoolbox-0.5.0a1.dist-info → tonietoolbox-0.6.0a1.dist-info}/WHEEL +1 -1
- tonietoolbox-0.5.0a1.dist-info/RECORD +0 -26
- {tonietoolbox-0.5.0a1.dist-info → tonietoolbox-0.6.0a1.dist-info}/entry_points.txt +0 -0
- {tonietoolbox-0.5.0a1.dist-info → tonietoolbox-0.6.0a1.dist-info}/licenses/LICENSE.md +0 -0
- {tonietoolbox-0.5.0a1.dist-info → tonietoolbox-0.6.0a1.dist-info}/top_level.txt +0 -0
TonieToolbox/__init__.py
CHANGED
TonieToolbox/__main__.py
CHANGED
@@ -10,18 +10,18 @@ import logging
|
|
10
10
|
from . import __version__
|
11
11
|
from .audio_conversion import get_input_files, append_to_filename
|
12
12
|
from .tonie_file import create_tonie_file
|
13
|
-
from .tonie_analysis import check_tonie_file, check_tonie_file_cli, split_to_opus_files
|
13
|
+
from .tonie_analysis import check_tonie_file, check_tonie_file_cli, split_to_opus_files, compare_taf_files
|
14
14
|
from .dependency_manager import get_ffmpeg_binary, get_opus_binary
|
15
|
-
from .logger import setup_logging, get_logger
|
15
|
+
from .logger import TRACE, setup_logging, get_logger
|
16
16
|
from .filename_generator import guess_output_filename
|
17
17
|
from .version_handler import check_for_updates, clear_version_cache
|
18
18
|
from .recursive_processor import process_recursive_folders
|
19
|
-
from .media_tags import is_available as is_media_tags_available, ensure_mutagen, extract_album_info, format_metadata_filename
|
19
|
+
from .media_tags import is_available as is_media_tags_available, ensure_mutagen, extract_album_info, format_metadata_filename, get_file_tags
|
20
20
|
from .teddycloud import TeddyCloudClient
|
21
21
|
from .tags import get_tags
|
22
|
-
from .tonies_json import
|
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
|
-
|
24
|
+
from .integration import handle_integration
|
25
25
|
|
26
26
|
def main():
|
27
27
|
"""Entry point for the TonieToolbox application."""
|
@@ -52,6 +52,8 @@ def main():
|
|
52
52
|
help='Delay between retry attempts in seconds (default: 5)')
|
53
53
|
teddycloud_group.add_argument('--create-custom-json', action='store_true',
|
54
54
|
help='Fetch and update custom Tonies JSON data')
|
55
|
+
teddycloud_group.add_argument('--version-2', action='store_true',
|
56
|
+
help='Use version 2 of the Tonies JSON format (default: version 1)')
|
55
57
|
# ------------- Parser - Authentication options for TeddyCloud -------------
|
56
58
|
teddycloud_group.add_argument('--username', action='store', metavar='USERNAME',
|
57
59
|
help='Username for basic authentication')
|
@@ -87,6 +89,8 @@ def main():
|
|
87
89
|
help='Save output files in the source directory instead of output directory')
|
88
90
|
parser.add_argument('-fc', '--force-creation', action='store_true', default=False,
|
89
91
|
help='Force creation of Tonie file even if it already exists')
|
92
|
+
parser.add_argument('--no-mono-conversion', action='store_true',
|
93
|
+
help='Do not convert mono audio to stereo (default: convert mono to stereo)')
|
90
94
|
# ------------- Parser - Debug TAFs -------------
|
91
95
|
parser.add_argument('-k', '--keep-temp', action='store_true',
|
92
96
|
help='Keep temporary opus files in a temp folder for testing')
|
@@ -95,7 +99,12 @@ def main():
|
|
95
99
|
parser.add_argument('-C', '--compare', action='store', metavar='FILE2',
|
96
100
|
help='Compare input file with another .taf file for debugging')
|
97
101
|
parser.add_argument('-D', '--detailed-compare', action='store_true',
|
98
|
-
help='Show detailed OGG page differences when comparing files')
|
102
|
+
help='Show detailed OGG page differences when comparing files')
|
103
|
+
# ------------- Parser - Context Menu Integration -------------
|
104
|
+
parser.add_argument('--install-integration', action='store_true',
|
105
|
+
help='Integrate with the system (e.g., create context menu entries)')
|
106
|
+
parser.add_argument('--uninstall-integration', action='store_true',
|
107
|
+
help='Uninstall context menu integration')
|
99
108
|
# ------------- Parser - Media Tag Options -------------
|
100
109
|
media_tag_group = parser.add_argument_group('Media Tag Options')
|
101
110
|
media_tag_group.add_argument('-m', '--use-media-tags', action='store_true',
|
@@ -124,12 +133,11 @@ def main():
|
|
124
133
|
args = parser.parse_args()
|
125
134
|
|
126
135
|
# ------------- Parser - Source Input -------------
|
127
|
-
if args.input_filename is None and not (args.get_tags or args.upload):
|
136
|
+
if args.input_filename is None and not (args.get_tags or args.upload or args.install_integration or args.uninstall_integration):
|
128
137
|
parser.error("the following arguments are required: SOURCE")
|
129
138
|
|
130
139
|
# ------------- Logging -------------
|
131
140
|
if args.trace:
|
132
|
-
from .logger import TRACE
|
133
141
|
log_level = TRACE
|
134
142
|
elif args.debug:
|
135
143
|
log_level = logging.DEBUG
|
@@ -164,7 +172,19 @@ def main():
|
|
164
172
|
|
165
173
|
if not is_latest and not update_confirmed and not (args.silent or args.quiet):
|
166
174
|
logger.info("Update available but user chose to continue without updating.")
|
167
|
-
|
175
|
+
# ------------- Context Menu Integration -------------
|
176
|
+
if args.install_integration or args.uninstall_integration:
|
177
|
+
logger.debug("Context menu integration requested: install=%s, uninstall=%s",
|
178
|
+
args.install_integration, args.uninstall_integration)
|
179
|
+
success = handle_integration(args)
|
180
|
+
if success:
|
181
|
+
if args.install_integration:
|
182
|
+
logger.info("Context menu integration installed successfully")
|
183
|
+
else:
|
184
|
+
logger.info("Context menu integration uninstalled successfully")
|
185
|
+
else:
|
186
|
+
logger.error("Failed to handle context menu integration")
|
187
|
+
sys.exit(0)
|
168
188
|
# ------------- Normalize Path Input -------------
|
169
189
|
if args.input_filename:
|
170
190
|
logger.debug("Original input path: %s", args.input_filename)
|
@@ -203,93 +223,91 @@ def main():
|
|
203
223
|
success = get_tags(client)
|
204
224
|
logger.debug( "Exiting with code %d", 0 if success else 1)
|
205
225
|
sys.exit(0 if success else 1)
|
206
|
-
|
207
|
-
# -------------
|
208
|
-
|
226
|
+
|
227
|
+
# ------------- Show Media Tags -------------
|
228
|
+
if args.show_tags:
|
229
|
+
files = get_input_files(args.input_filename)
|
230
|
+
logger.debug("Found %d files to process", len(files))
|
231
|
+
if len(files) == 0:
|
232
|
+
logger.error("No files found for pattern %s", args.input_filename)
|
233
|
+
sys.exit(1)
|
234
|
+
for file_index, file_path in enumerate(files):
|
235
|
+
tags = get_file_tags(file_path)
|
236
|
+
if tags:
|
237
|
+
print(f"\nFile {file_index + 1}: {os.path.basename(file_path)}")
|
238
|
+
print("-" * 40)
|
239
|
+
for tag_name, tag_value in sorted(tags.items()):
|
240
|
+
print(f"{tag_name}: {tag_value}")
|
241
|
+
else:
|
242
|
+
print(f"\nFile {file_index + 1}: {os.path.basename(file_path)} - No tags found")
|
243
|
+
sys.exit(0)
|
244
|
+
# ------------- Direct Upload -------------
|
245
|
+
if os.path.exists(args.input_filename) and os.path.isfile(args.input_filename):
|
246
|
+
file_path = args.input_filename
|
247
|
+
file_size = os.path.getsize(file_path)
|
248
|
+
file_ext = os.path.splitext(file_path)[1].lower()
|
249
|
+
|
250
|
+
if args.upload and not args.recursive and file_ext == '.taf':
|
209
251
|
logger.debug("Upload to TeddyCloud requested: %s", teddycloud_url)
|
210
252
|
logger.trace("TeddyCloud upload parameters: path=%s, special_folder=%s, ignore_ssl=%s",
|
211
253
|
args.path, args.special_folder, args.ignore_ssl_verify)
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
254
|
+
logger.debug("File to upload: %s (size: %d bytes, type: %s)",
|
255
|
+
file_path, file_size, file_ext)
|
256
|
+
logger.info("Uploading %s to TeddyCloud %s", file_path, teddycloud_url)
|
257
|
+
logger.trace("Starting upload process for %s", file_path)
|
258
|
+
response = client.upload_file(
|
259
|
+
destination_path=args.path,
|
260
|
+
file_path=file_path,
|
261
|
+
special=args.special_folder,
|
262
|
+
)
|
263
|
+
logger.trace("Upload response received: %s", response)
|
264
|
+
upload_success = response.get('success', False)
|
265
|
+
if not upload_success:
|
266
|
+
error_msg = response.get('message', 'Unknown error')
|
267
|
+
logger.error("Failed to upload %s to TeddyCloud: %s (HTTP Status: %s, Response: %s)",
|
268
|
+
file_path, error_msg, response.get('status_code', 'Unknown'), response)
|
269
|
+
logger.trace("Exiting with code 1 due to upload failure")
|
216
270
|
sys.exit(1)
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
logger.
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
logger.trace("Upload response received: %s", response)
|
234
|
-
|
235
|
-
upload_success = response.get('success', False)
|
236
|
-
if not upload_success:
|
237
|
-
error_msg = response.get('message', 'Unknown error')
|
238
|
-
logger.error("Failed to upload %s to TeddyCloud: %s", file_path, error_msg)
|
239
|
-
logger.trace("Exiting with code 1 due to upload failure")
|
240
|
-
sys.exit(1)
|
271
|
+
else:
|
272
|
+
logger.info("Successfully uploaded %s to TeddyCloud", file_path)
|
273
|
+
logger.debug("Upload response details: %s",
|
274
|
+
{k: v for k, v in response.items() if k != 'success'})
|
275
|
+
artwork_url = None
|
276
|
+
if args.include_artwork and file_path.lower().endswith('.taf'):
|
277
|
+
source_dir = os.path.dirname(file_path)
|
278
|
+
logger.info("Looking for artwork to upload for %s", file_path)
|
279
|
+
logger.debug("Searching for artwork in directory: %s", source_dir)
|
280
|
+
logger.trace("Calling upload_artwork function")
|
281
|
+
success, artwork_url = upload_artwork(client, file_path, source_dir, [])
|
282
|
+
logger.trace("upload_artwork returned: success=%s, artwork_url=%s",
|
283
|
+
success, artwork_url)
|
284
|
+
if success:
|
285
|
+
logger.info("Successfully uploaded artwork for %s", file_path)
|
286
|
+
logger.debug("Artwork URL: %s", artwork_url)
|
241
287
|
else:
|
242
|
-
logger.
|
243
|
-
logger.debug("
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
if
|
248
|
-
|
249
|
-
logger.
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
logger.
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
output_dir = './output'
|
266
|
-
logger.debug("Creating/ensuring output directory for JSON: %s", output_dir)
|
267
|
-
if not os.path.exists(output_dir):
|
268
|
-
os.makedirs(output_dir, exist_ok=True)
|
269
|
-
logger.trace("Created output directory: %s", output_dir)
|
270
|
-
|
271
|
-
logger.debug("Updating tonies.custom.json with: taf=%s, artwork_url=%s",
|
272
|
-
file_path, artwork_url)
|
273
|
-
success = fetch_and_update_tonies_json(client, file_path, [], artwork_url, output_dir)
|
274
|
-
if success:
|
275
|
-
logger.info("Successfully updated Tonies JSON for %s", file_path)
|
276
|
-
else:
|
277
|
-
logger.warning("Failed to update Tonies JSON for %s", file_path)
|
278
|
-
logger.debug("fetch_and_update_tonies_json returned failure")
|
279
|
-
|
280
|
-
logger.trace("Exiting after direct upload with code 0")
|
281
|
-
sys.exit(0)
|
282
|
-
elif not args.recursive:
|
283
|
-
logger.error("File not found or not a regular file: %s", args.input_filename)
|
284
|
-
logger.debug("File exists: %s, Is file: %s",
|
285
|
-
os.path.exists(args.input_filename),
|
286
|
-
os.path.isfile(args.input_filename) if os.path.exists(args.input_filename) else False)
|
287
|
-
logger.trace("Exiting with code 1 due to invalid input file")
|
288
|
-
sys.exit(1)
|
289
|
-
|
290
|
-
if args.recursive and args.upload:
|
291
|
-
logger.info("Recursive mode with upload enabled: %s -> %s", args.input_filename, teddycloud_url)
|
292
|
-
logger.debug("Will process all files in directory recursively and upload to TeddyCloud")
|
288
|
+
logger.warning("Failed to upload artwork for %s", file_path)
|
289
|
+
logger.debug("No suitable artwork found or upload failed")
|
290
|
+
if args.create_custom_json and file_path.lower().endswith('.taf'):
|
291
|
+
output_dir = './output'
|
292
|
+
logger.debug("Creating/ensuring output directory for JSON: %s", output_dir)
|
293
|
+
if not os.path.exists(output_dir):
|
294
|
+
os.makedirs(output_dir, exist_ok=True)
|
295
|
+
logger.trace("Created output directory: %s", output_dir)
|
296
|
+
logger.debug("Updating tonies.custom.json with: taf=%s, artwork_url=%s",
|
297
|
+
file_path, artwork_url)
|
298
|
+
client_param = client
|
299
|
+
if args.version_2:
|
300
|
+
logger.debug("Using version 2 of the Tonies JSON format")
|
301
|
+
success = fetch_and_update_tonies_json_v2(client_param, file_path, [], artwork_url, output_dir)
|
302
|
+
else:
|
303
|
+
success = fetch_and_update_tonies_json_v1(client_param, file_path, [], artwork_url, output_dir)
|
304
|
+
if success:
|
305
|
+
logger.info("Successfully updated Tonies JSON for %s", file_path)
|
306
|
+
else:
|
307
|
+
logger.warning("Failed to update Tonies JSON for %s", file_path)
|
308
|
+
logger.debug("fetch_and_update_tonies_json returned failure")
|
309
|
+
logger.trace("Exiting after direct upload with code 0")
|
310
|
+
sys.exit(0)
|
293
311
|
|
294
312
|
# ------------- Librarys / Prereqs -------------
|
295
313
|
logger.debug("Checking for external dependencies")
|
@@ -364,10 +382,16 @@ def main():
|
|
364
382
|
if not skip_creation:
|
365
383
|
create_tonie_file(task_out_filename, audio_files, args.no_tonie_header, args.user_timestamp,
|
366
384
|
args.bitrate, not args.cbr, ffmpeg_binary, opus_binary, args.keep_temp,
|
367
|
-
args.auto_download, not args.use_legacy_tags
|
385
|
+
args.auto_download, not args.use_legacy_tags,
|
386
|
+
no_mono_conversion=args.no_mono_conversion)
|
368
387
|
logger.info("Successfully created Tonie file: %s", task_out_filename)
|
369
388
|
|
370
389
|
created_files.append(task_out_filename)
|
390
|
+
|
391
|
+
# ------------- Initialization -------------------
|
392
|
+
|
393
|
+
artwork_url = None
|
394
|
+
|
371
395
|
# ------------- Recursive File Upload -------------
|
372
396
|
if args.upload:
|
373
397
|
response = client.upload_file(
|
@@ -391,12 +415,19 @@ def main():
|
|
391
415
|
logger.warning("Failed to upload artwork for %s", task_out_filename)
|
392
416
|
|
393
417
|
# tonies.custom.json generation
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
418
|
+
if args.create_custom_json:
|
419
|
+
base_path = os.path.dirname(args.input_filename)
|
420
|
+
json_output_dir = base_path if args.output_to_source else output_dir
|
421
|
+
client_param = client if 'client' in locals() else None
|
422
|
+
if args.version_2:
|
423
|
+
logger.debug("Using version 2 of the Tonies JSON format")
|
424
|
+
success = fetch_and_update_tonies_json_v2(client_param, task_out_filename, audio_files, artwork_url, json_output_dir)
|
425
|
+
else:
|
426
|
+
success = fetch_and_update_tonies_json_v1(client_param, task_out_filename, audio_files, artwork_url, json_output_dir)
|
427
|
+
if success:
|
428
|
+
logger.info("Successfully updated Tonies JSON for %s", task_out_filename)
|
429
|
+
else:
|
430
|
+
logger.warning("Failed to update Tonies JSON for %s", task_out_filename)
|
400
431
|
|
401
432
|
logger.info("Recursive processing completed. Created %d Tonie files.", len(process_tasks))
|
402
433
|
sys.exit(0)
|
@@ -415,7 +446,6 @@ def main():
|
|
415
446
|
split_to_opus_files(args.input_filename, args.output_filename)
|
416
447
|
sys.exit(0)
|
417
448
|
elif args.compare:
|
418
|
-
from .tonie_analysis import compare_taf_files
|
419
449
|
logger.info("Comparing Tonie files: %s and %s", args.input_filename, args.compare)
|
420
450
|
result = compare_taf_files(args.input_filename, args.compare, args.detailed_compare)
|
421
451
|
sys.exit(0 if result else 1)
|
@@ -426,26 +456,12 @@ def main():
|
|
426
456
|
if len(files) == 0:
|
427
457
|
logger.error("No files found for pattern %s", args.input_filename)
|
428
458
|
sys.exit(1)
|
429
|
-
|
430
|
-
from .media_tags import get_file_tags
|
431
|
-
logger.info("Showing media tags for input files:")
|
432
|
-
|
433
|
-
for file_index, file_path in enumerate(files):
|
434
|
-
tags = get_file_tags(file_path)
|
435
|
-
if tags:
|
436
|
-
print(f"\nFile {file_index + 1}: {os.path.basename(file_path)}")
|
437
|
-
print("-" * 40)
|
438
|
-
for tag_name, tag_value in sorted(tags.items()):
|
439
|
-
print(f"{tag_name}: {tag_value}")
|
440
|
-
else:
|
441
|
-
print(f"\nFile {file_index + 1}: {os.path.basename(file_path)} - No tags found")
|
442
|
-
sys.exit(0)
|
459
|
+
|
443
460
|
guessed_name = None
|
444
461
|
if args.use_media_tags:
|
445
462
|
if len(files) > 1 and os.path.dirname(files[0]) == os.path.dirname(files[-1]):
|
446
463
|
folder_path = os.path.dirname(files[0])
|
447
|
-
logger.debug("Extracting album info from folder: %s", folder_path)
|
448
|
-
|
464
|
+
logger.debug("Extracting album info from folder: %s", folder_path)
|
449
465
|
album_info = extract_album_info(folder_path)
|
450
466
|
if album_info:
|
451
467
|
template = args.name_template or "{album} - {artist}"
|
@@ -457,7 +473,7 @@ def main():
|
|
457
473
|
else:
|
458
474
|
logger.debug("Could not format filename from album metadata")
|
459
475
|
elif len(files) == 1:
|
460
|
-
|
476
|
+
|
461
477
|
|
462
478
|
tags = get_file_tags(files[0])
|
463
479
|
if tags:
|
@@ -471,9 +487,7 @@ def main():
|
|
471
487
|
logger.debug("Could not format filename from file metadata")
|
472
488
|
|
473
489
|
# For multiple files from different folders, try to use common tags if they exist
|
474
|
-
elif len(files) > 1:
|
475
|
-
from .media_tags import get_file_tags, format_metadata_filename
|
476
|
-
|
490
|
+
elif len(files) > 1:
|
477
491
|
# Try to find common tags among files
|
478
492
|
common_tags = {}
|
479
493
|
for file_path in files:
|
@@ -547,7 +561,8 @@ def main():
|
|
547
561
|
logger.info("Creating Tonie file: %s with %d input file(s)", out_filename, len(files))
|
548
562
|
create_tonie_file(out_filename, files, args.no_tonie_header, args.user_timestamp,
|
549
563
|
args.bitrate, not args.cbr, ffmpeg_binary, opus_binary, args.keep_temp,
|
550
|
-
args.auto_download, not args.use_legacy_tags
|
564
|
+
args.auto_download, not args.use_legacy_tags,
|
565
|
+
no_mono_conversion=args.no_mono_conversion)
|
551
566
|
logger.info("Successfully created Tonie file: %s", out_filename)
|
552
567
|
|
553
568
|
# ------------- Single File Upload -------------
|
@@ -571,13 +586,19 @@ def main():
|
|
571
586
|
logger.info("Successfully uploaded artwork for %s", out_filename)
|
572
587
|
else:
|
573
588
|
logger.warning("Failed to upload artwork for %s", out_filename)
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
589
|
+
|
590
|
+
if args.create_custom_json:
|
591
|
+
json_output_dir = source_dir if args.output_to_source else './output'
|
592
|
+
client_param = client if 'client' in locals() else None
|
593
|
+
if args.version_2:
|
594
|
+
logger.debug("Using version 2 of the Tonies JSON format")
|
595
|
+
success = fetch_and_update_tonies_json_v2(client_param, out_filename, files, artwork_url, json_output_dir)
|
596
|
+
else:
|
597
|
+
success = fetch_and_update_tonies_json_v1(client_param, out_filename, files, artwork_url, json_output_dir)
|
598
|
+
if success:
|
599
|
+
logger.info("Successfully updated Tonies JSON for %s", out_filename)
|
600
|
+
else:
|
601
|
+
logger.warning("Failed to update Tonies JSON for %s", out_filename)
|
581
602
|
|
582
603
|
if __name__ == "__main__":
|
583
604
|
main()
|
TonieToolbox/artwork.py
CHANGED
@@ -13,17 +13,22 @@ from .teddycloud import TeddyCloudClient
|
|
13
13
|
from .media_tags import extract_artwork, find_cover_image
|
14
14
|
|
15
15
|
|
16
|
-
def upload_artwork(
|
16
|
+
def upload_artwork(
|
17
|
+
client: TeddyCloudClient,
|
18
|
+
taf_filename: str,
|
19
|
+
source_path: str,
|
20
|
+
audio_files: list[str],
|
21
|
+
) -> tuple[bool, Optional[str]]:
|
17
22
|
"""
|
18
23
|
Find and upload artwork for a Tonie file.
|
19
|
-
|
24
|
+
|
20
25
|
Args:
|
21
|
-
client: TeddyCloudClient instance to use for API communication
|
22
|
-
taf_filename: The filename of the Tonie file (.taf)
|
23
|
-
source_path: Source directory to look for artwork
|
24
|
-
audio_files: List of audio files to extract artwork from if needed
|
26
|
+
client (TeddyCloudClient): TeddyCloudClient instance to use for API communication
|
27
|
+
taf_filename (str): The filename of the Tonie file (.taf)
|
28
|
+
source_path (str): Source directory to look for artwork
|
29
|
+
audio_files (list[str]): List of audio files to extract artwork from if needed
|
25
30
|
Returns:
|
26
|
-
tuple: (success, artwork_url) where success is a boolean and artwork_url is the URL of the uploaded artwork
|
31
|
+
tuple[bool, Optional[str]]: (success, artwork_url) where success is a boolean and artwork_url is the URL of the uploaded artwork
|
27
32
|
"""
|
28
33
|
logger = get_logger('artwork')
|
29
34
|
logger.info("Looking for artwork for Tonie file: %s", taf_filename)
|