TonieToolbox 0.2.0__py3-none-any.whl → 0.2.2__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.2.0'
5
+ __version__ = '0.2.2'
TonieToolbox/__main__.py CHANGED
@@ -21,50 +21,52 @@ from .recursive_processor import process_recursive_folders
21
21
  def main():
22
22
  """Entry point for the TonieToolbox application."""
23
23
  parser = argparse.ArgumentParser(description='Create Tonie compatible file from Ogg opus file(s).')
24
- parser.add_argument('--version', action='version', version=f'TonieToolbox {__version__}',
24
+ parser.add_argument('-v', '--version', action='version', version=f'TonieToolbox {__version__}',
25
25
  help='show program version and exit')
26
26
  parser.add_argument('input_filename', metavar='SOURCE', type=str,
27
27
  help='input file or directory or a file list (.lst)')
28
28
  parser.add_argument('output_filename', metavar='TARGET', nargs='?', type=str,
29
29
  help='the output file name (default: ---ID---)')
30
- parser.add_argument('--ts', dest='user_timestamp', metavar='TIMESTAMP', action='store',
30
+ parser.add_argument('-t', '--timestamp', dest='user_timestamp', metavar='TIMESTAMP', action='store',
31
31
  help='set custom timestamp / bitstream serial')
32
32
 
33
- parser.add_argument('--ffmpeg', help='specify location of ffmpeg', default=None)
34
- parser.add_argument('--opusenc', help='specify location of opusenc', default=None)
35
- parser.add_argument('--bitrate', type=int, help='set encoding bitrate in kbps (default: 96)', default=96)
36
- parser.add_argument('--cbr', action='store_true', help='encode in cbr mode')
37
- parser.add_argument('--append-tonie-tag', metavar='TAG', action='store',
33
+ parser.add_argument('-f', '--ffmpeg', help='specify location of ffmpeg', default=None)
34
+ parser.add_argument('-o', '--opusenc', help='specify location of opusenc', default=None)
35
+ parser.add_argument('-b', '--bitrate', type=int, help='set encoding bitrate in kbps (default: 96)', default=96)
36
+ parser.add_argument('-c', '--cbr', action='store_true', help='encode in cbr mode')
37
+ parser.add_argument('-a', '--append-tonie-tag', metavar='TAG', action='store',
38
38
  help='append [TAG] to filename (must be an 8-character hex value)')
39
- parser.add_argument('--no-tonie-header', action='store_true', help='do not write Tonie header')
40
- parser.add_argument('--info', action='store_true', help='Check and display info about Tonie file')
41
- parser.add_argument('--split', action='store_true', help='Split Tonie file into opus tracks')
42
- parser.add_argument('--recursive', action='store_true', help='Process folders recursively')
43
- parser.add_argument('--output-to-source', action='store_true',
39
+ parser.add_argument('-n', '--no-tonie-header', action='store_true', help='do not write Tonie header')
40
+ parser.add_argument('-i', '--info', action='store_true', help='Check and display info about Tonie file')
41
+ parser.add_argument('-s', '--split', action='store_true', help='Split Tonie file into opus tracks')
42
+ parser.add_argument('-r', '--recursive', action='store_true', help='Process folders recursively')
43
+ parser.add_argument('-O', '--output-to-source', action='store_true',
44
44
  help='Save output files in the source directory instead of output directory')
45
- parser.add_argument('--auto-download', action='store_true', help='Automatically download FFmpeg and opusenc if needed')
46
- parser.add_argument('--keep-temp', action='store_true',
45
+ parser.add_argument('-A', '--auto-download', action='store_true', help='Automatically download FFmpeg and opusenc if needed')
46
+ parser.add_argument('-k', '--keep-temp', action='store_true',
47
47
  help='Keep temporary opus files in a temp folder for testing')
48
- parser.add_argument('--compare', action='store', metavar='FILE2',
48
+ parser.add_argument('-u', '--use-legacy-tags', action='store_true',
49
+ help='Use legacy hardcoded tags instead of dynamic TonieToolbox tags')
50
+ parser.add_argument('-C', '--compare', action='store', metavar='FILE2',
49
51
  help='Compare input file with another .taf file for debugging')
50
- parser.add_argument('--detailed-compare', action='store_true',
52
+ parser.add_argument('-D', '--detailed-compare', action='store_true',
51
53
  help='Show detailed OGG page differences when comparing files')
52
54
 
53
55
  # Version check options
54
56
  version_group = parser.add_argument_group('Version Check Options')
55
- version_group.add_argument('--skip-update-check', action='store_true',
57
+ version_group.add_argument('-S', '--skip-update-check', action='store_true',
56
58
  help='Skip checking for updates')
57
- version_group.add_argument('--force-refresh-cache', action='store_true',
59
+ version_group.add_argument('-F', '--force-refresh-cache', action='store_true',
58
60
  help='Force refresh of update information from PyPI')
59
- version_group.add_argument('--clear-version-cache', action='store_true',
61
+ version_group.add_argument('-X', '--clear-version-cache', action='store_true',
60
62
  help='Clear cached version information')
61
63
 
62
64
  log_group = parser.add_argument_group('Logging Options')
63
65
  log_level_group = log_group.add_mutually_exclusive_group()
64
- log_level_group.add_argument('--debug', action='store_true', help='Enable debug logging')
65
- log_level_group.add_argument('--trace', action='store_true', help='Enable trace logging (very verbose)')
66
- log_level_group.add_argument('--quiet', action='store_true', help='Show only warnings and errors')
67
- log_level_group.add_argument('--silent', action='store_true', help='Show only errors')
66
+ log_level_group.add_argument('-d', '--debug', action='store_true', help='Enable debug logging')
67
+ log_level_group.add_argument('-T', '--trace', action='store_true', help='Enable trace logging (very verbose)')
68
+ log_level_group.add_argument('-q', '--quiet', action='store_true', help='Show only warnings and errors')
69
+ log_level_group.add_argument('-Q', '--silent', action='store_true', help='Show only errors')
68
70
 
69
71
  args = parser.parse_args()
70
72
  if args.trace:
@@ -143,7 +145,7 @@ def main():
143
145
 
144
146
  create_tonie_file(task_out_filename, audio_files, args.no_tonie_header, args.user_timestamp,
145
147
  args.bitrate, not args.cbr, ffmpeg_binary, opus_binary, args.keep_temp,
146
- args.auto_download)
148
+ args.auto_download, not args.use_legacy_tags)
147
149
  logger.info("Successfully created Tonie file: %s", task_out_filename)
148
150
 
149
151
  logger.info("Recursive processing completed. Created %d Tonie files.", len(process_tasks))
@@ -207,7 +209,8 @@ def main():
207
209
 
208
210
  logger.info("Creating Tonie file: %s with %d input file(s)", out_filename, len(files))
209
211
  create_tonie_file(out_filename, files, args.no_tonie_header, args.user_timestamp,
210
- args.bitrate, not args.cbr, ffmpeg_binary, opus_binary, args.keep_temp, args.auto_download)
212
+ args.bitrate, not args.cbr, ffmpeg_binary, opus_binary, args.keep_temp,
213
+ args.auto_download, not args.use_legacy_tags)
211
214
  logger.info("Successfully created Tonie file: %s", out_filename)
212
215
 
213
216
 
@@ -532,4 +532,49 @@ def get_opus_binary(auto_download=False):
532
532
  Returns:
533
533
  str: Path to the opusenc binary if available, None otherwise
534
534
  """
535
- return ensure_dependency('opusenc', auto_download)
535
+ return ensure_dependency('opusenc', auto_download)
536
+
537
+ def get_opus_version(opus_binary=None):
538
+ """
539
+ Get the version of opusenc.
540
+
541
+ Args:
542
+ opus_binary: Path to the opusenc binary
543
+
544
+ Returns:
545
+ str: The version string of opusenc, or a fallback string if the version cannot be determined
546
+ """
547
+ import subprocess
548
+ import re
549
+
550
+ logger = get_logger('dependency_manager')
551
+
552
+ if opus_binary is None:
553
+ opus_binary = get_opus_binary()
554
+
555
+ if opus_binary is None:
556
+ logger.debug("opusenc binary not found, using fallback version string")
557
+ return "opusenc from opus-tools XXX" # Fallback
558
+
559
+ try:
560
+ # Run opusenc --version and capture output
561
+ result = subprocess.run([opus_binary, "--version"],
562
+ capture_output=True, text=True, check=False)
563
+
564
+ # Extract version information from output
565
+ version_output = result.stdout.strip() or result.stderr.strip()
566
+
567
+ if version_output:
568
+ # Try to extract just the version information using regex
569
+ match = re.search(r"(opusenc.*)", version_output)
570
+ if match:
571
+ return match.group(1)
572
+ else:
573
+ return version_output.splitlines()[0] # Use first line
574
+ else:
575
+ logger.debug("Could not determine opusenc version, using fallback")
576
+ return "opusenc from opus-tools XXX" # Fallback
577
+
578
+ except Exception as e:
579
+ logger.debug(f"Error getting opusenc version: {str(e)}")
580
+ return "opusenc from opus-tools XXX" # Fallback
@@ -72,7 +72,8 @@ def get_header_info(in_file):
72
72
 
73
73
  Returns:
74
74
  tuple: Header size, Tonie header object, file size, audio size, SHA1 sum,
75
- Opus header found flag, Opus version, channel count, sample rate, bitstream serial number
75
+ Opus header found flag, Opus version, channel count, sample rate, bitstream serial number,
76
+ Opus comments dictionary
76
77
 
77
78
  Raises:
78
79
  RuntimeError: If OGG pages cannot be found
@@ -112,17 +113,64 @@ def get_header_info(in_file):
112
113
  logger.debug("Opus header found: %s, Version: %d, Channels: %d, Sample rate: %d Hz, Serial: %d",
113
114
  opus_head_found, opus_version, channel_count, sample_rate, bitstream_serial_no)
114
115
 
116
+ # Read and parse Opus comments from the second page
117
+ opus_comments = {}
115
118
  found = OggPage.seek_to_page_header(in_file)
116
119
  if not found:
117
120
  logger.error("Second OGG page not found")
118
121
  raise RuntimeError("Second ogg page not found")
119
122
 
120
- OggPage(in_file)
123
+ second_page = OggPage(in_file)
121
124
  logger.debug("Read second OGG page")
125
+
126
+ try:
127
+ # Combine all segments data for the second page
128
+ comment_data = bytearray()
129
+ for segment in second_page.segments:
130
+ comment_data.extend(segment.data)
131
+
132
+ if comment_data.startswith(b"OpusTags"):
133
+ pos = 8 # Skip "OpusTags"
134
+ # Extract vendor string
135
+ if pos + 4 <= len(comment_data):
136
+ vendor_length = struct.unpack("<I", comment_data[pos:pos+4])[0]
137
+ pos += 4
138
+ if pos + vendor_length <= len(comment_data):
139
+ vendor = comment_data[pos:pos+vendor_length].decode('utf-8', errors='replace')
140
+ opus_comments["vendor"] = vendor
141
+ pos += vendor_length
142
+
143
+ # Extract comments count
144
+ if pos + 4 <= len(comment_data):
145
+ comments_count = struct.unpack("<I", comment_data[pos:pos+4])[0]
146
+ pos += 4
147
+
148
+ # Extract individual comments
149
+ for i in range(comments_count):
150
+ if pos + 4 <= len(comment_data):
151
+ comment_length = struct.unpack("<I", comment_data[pos:pos+4])[0]
152
+ pos += 4
153
+ if pos + comment_length <= len(comment_data):
154
+ comment = comment_data[pos:pos+comment_length].decode('utf-8', errors='replace')
155
+ pos += comment_length
156
+
157
+ # Split comment into key/value if possible
158
+ if "=" in comment:
159
+ key, value = comment.split("=", 1)
160
+ opus_comments[key] = value
161
+ else:
162
+ opus_comments[f"comment_{i}"] = comment
163
+ else:
164
+ break
165
+ else:
166
+ break
167
+ except Exception as e:
168
+ logger.error("Failed to parse Opus comments: %s", str(e))
122
169
 
123
170
  return (
124
171
  header_size, tonie_header, file_size, audio_size, sha1sum,
125
- opus_head_found, opus_version, channel_count, sample_rate, bitstream_serial_no
172
+ opus_head_found, opus_version, channel_count, sample_rate, bitstream_serial_no,
173
+ opus_comments
126
174
  )
127
175
 
128
176
 
@@ -204,7 +252,7 @@ def check_tonie_file(filename):
204
252
 
205
253
  with open(filename, "rb") as in_file:
206
254
  header_size, tonie_header, file_size, audio_size, sha1, opus_head_found, \
207
- opus_version, channel_count, sample_rate, bitstream_serial_no = get_header_info(in_file)
255
+ opus_version, channel_count, sample_rate, bitstream_serial_no, opus_comments = get_header_info(in_file)
208
256
 
209
257
  page_count, alignment_okay, page_size_okay, total_time, \
210
258
  chapters = get_audio_info(in_file, sample_rate, tonie_header, header_size)
@@ -254,6 +302,20 @@ def check_tonie_file(filename):
254
302
  print("")
255
303
  print("[{}] File is {}valid".format("OK" if all_ok else "NOT OK", "" if all_ok else "NOT "))
256
304
  print("")
305
+
306
+ # Display Opus comments if available
307
+ if opus_comments:
308
+ print("[ii] Opus Comments:")
309
+ if "vendor" in opus_comments:
310
+ print(" Vendor: {}".format(opus_comments["vendor"]))
311
+ # Remove vendor from dict to avoid showing it twice
312
+ vendor = opus_comments.pop("vendor")
313
+
314
+ # Sort remaining comments for consistent display
315
+ for key in sorted(opus_comments.keys()):
316
+ print(" {}: {}".format(key, opus_comments[key]))
317
+ print("")
318
+
257
319
  print("[ii] Total runtime: {}".format(granule_to_time_string(total_time)))
258
320
  print("[ii] {} Tracks:".format(len(chapters)))
259
321
  for i in range(0, len(chapters)):
@@ -19,6 +19,33 @@ from .logger import get_logger
19
19
  logger = get_logger('tonie_file')
20
20
 
21
21
 
22
+ def toniefile_comment_add(buffer, length, comment_str):
23
+ """
24
+ Add a comment string to an Opus comment packet buffer.
25
+
26
+ Args:
27
+ buffer: Bytearray buffer to add comment to
28
+ length: Current position in the buffer
29
+ comment_str: Comment string to add
30
+
31
+ Returns:
32
+ int: New position in the buffer after adding comment
33
+ """
34
+ logger.debug("Adding comment: %s", comment_str)
35
+
36
+ # Add 4-byte length prefix
37
+ str_length = len(comment_str)
38
+ buffer[length:length+4] = struct.pack("<I", str_length)
39
+ length += 4
40
+
41
+ # Add the actual string
42
+ buffer[length:length+str_length] = comment_str.encode('utf-8')
43
+ length += str_length
44
+
45
+ logger.trace("Added comment of length %d, new buffer position: %d", str_length, length)
46
+ return length
47
+
48
+
22
49
  def check_identification_header(page):
23
50
  """
24
51
  Check if a page contains a valid Opus identification header.
@@ -52,37 +79,103 @@ def check_identification_header(page):
52
79
  logger.debug("Opus identification header is valid")
53
80
 
54
81
 
55
- def prepare_opus_tags(page):
82
+ def prepare_opus_tags(page, custom_tags=False, bitrate=64, vbr=True, opus_binary=None):
56
83
  """
57
84
  Prepare standard Opus tags for a Tonie file.
58
85
 
59
86
  Args:
60
87
  page: OggPage to modify
88
+ custom_tags: Whether to use custom TonieToolbox tags instead of default ones
89
+ bitrate: Actual bitrate used for encoding
90
+ vbr: Whether variable bitrate was used
91
+ opus_binary: Path to opusenc binary for version detection
61
92
 
62
93
  Returns:
63
94
  OggPage: Modified page with Tonie-compatible Opus tags
64
95
  """
65
96
  logger.debug("Preparing Opus tags for Tonie compatibility")
66
97
  page.segments.clear()
67
- segment = OpusPacket(None)
68
- segment.size = len(OPUS_TAGS[0])
69
- segment.data = bytearray(OPUS_TAGS[0])
70
- segment.spanning_packet = True
71
- segment.first_packet = True
72
- page.segments.append(segment)
73
-
74
- segment = OpusPacket(None)
75
- segment.size = len(OPUS_TAGS[1])
76
- segment.data = bytearray(OPUS_TAGS[1])
77
- segment.spanning_packet = False
78
- segment.first_packet = False
79
- page.segments.append(segment)
98
+
99
+ if not custom_tags:
100
+ # Use the default hardcoded tags for backward compatibility
101
+ segment = OpusPacket(None)
102
+ segment.size = len(OPUS_TAGS[0])
103
+ segment.data = bytearray(OPUS_TAGS[0])
104
+ segment.spanning_packet = True
105
+ segment.first_packet = True
106
+ page.segments.append(segment)
107
+
108
+ segment = OpusPacket(None)
109
+ segment.size = len(OPUS_TAGS[1])
110
+ segment.data = bytearray(OPUS_TAGS[1])
111
+ segment.spanning_packet = False
112
+ segment.first_packet = False
113
+ page.segments.append(segment)
114
+ else:
115
+ # Use custom tags for TonieToolbox
116
+ # Create buffer for opus tags (similar to teddyCloud implementation)
117
+ logger.debug("Creating custom Opus tags")
118
+ comment_data = bytearray(0x1B4) # Same size as in teddyCloud
119
+
120
+ # OpusTags signature
121
+ comment_data_pos = 0
122
+ comment_data[comment_data_pos:comment_data_pos+8] = b"OpusTags"
123
+ comment_data_pos += 8
124
+
125
+ # Vendor string
126
+ comment_data_pos = toniefile_comment_add(comment_data, comment_data_pos, "TonieToolbox")
127
+
128
+ # Number of comments (3 comments: version, encoder info, and encoder options)
129
+ comments_count = 3
130
+ comment_data[comment_data_pos:comment_data_pos+4] = struct.pack("<I", comments_count)
131
+ comment_data_pos += 4
132
+
133
+ # Add version information
134
+ from . import __version__
135
+ version_str = f"version={__version__}"
136
+ comment_data_pos = toniefile_comment_add(comment_data, comment_data_pos, version_str)
137
+
138
+ # Get actual opusenc version
139
+ from .dependency_manager import get_opus_version
140
+ encoder_info = get_opus_version(opus_binary)
141
+ comment_data_pos = toniefile_comment_add(comment_data, comment_data_pos, f"encoder={encoder_info}")
142
+
143
+ # Create encoder options string with actual settings
144
+ vbr_opt = "--vbr" if vbr else "--cbr"
145
+ encoder_options = f"encoder_options=--bitrate {bitrate} {vbr_opt}"
146
+ comment_data_pos = toniefile_comment_add(comment_data, comment_data_pos, encoder_options)
147
+
148
+ # Add padding
149
+ remain = len(comment_data) - comment_data_pos - 4
150
+ comment_data[comment_data_pos:comment_data_pos+4] = struct.pack("<I", remain)
151
+ comment_data_pos += 4
152
+ comment_data[comment_data_pos:comment_data_pos+4] = b"pad="
153
+
154
+ # Create segments - handle data in chunks of 255 bytes maximum
155
+ comment_data = comment_data[:comment_data_pos + remain] # Trim to actual used size
156
+
157
+ # Split large data into smaller segments (each <= 255 bytes)
158
+ remaining_data = comment_data
159
+ first_segment = True
160
+
161
+ while remaining_data:
162
+ chunk_size = min(255, len(remaining_data))
163
+ segment = OpusPacket(None)
164
+ segment.size = chunk_size
165
+ segment.data = remaining_data[:chunk_size]
166
+ segment.spanning_packet = len(remaining_data) > chunk_size # More data follows
167
+ segment.first_packet = first_segment
168
+ page.segments.append(segment)
169
+
170
+ remaining_data = remaining_data[chunk_size:]
171
+ first_segment = False
172
+
80
173
  page.correct_values(0)
81
174
  logger.trace("Opus tags prepared with %d segments", len(page.segments))
82
175
  return page
83
176
 
84
177
 
85
- def copy_first_and_second_page(in_file, out_file, timestamp, sha):
178
+ def copy_first_and_second_page(in_file, out_file, timestamp, sha, use_custom_tags=True, bitrate=64, vbr=True, opus_binary=None):
86
179
  """
87
180
  Copy and modify the first two pages of an Opus file for a Tonie file.
88
181
 
@@ -91,9 +184,10 @@ def copy_first_and_second_page(in_file, out_file, timestamp, sha):
91
184
  out_file: Output file handle
92
185
  timestamp: Timestamp to use for the Tonie file
93
186
  sha: SHA1 hash object to update with written data
94
-
95
- Raises:
96
- RuntimeError: If OGG pages cannot be found
187
+ use_custom_tags: Whether to use custom TonieToolbox tags
188
+ bitrate: Actual bitrate used for encoding
189
+ vbr: Whether VBR was used
190
+ opus_binary: Path to opusenc binary
97
191
  """
98
192
  logger.debug("Copying first and second pages with timestamp %d", timestamp)
99
193
  found = OggPage.seek_to_page_header(in_file)
@@ -116,7 +210,7 @@ def copy_first_and_second_page(in_file, out_file, timestamp, sha):
116
210
  page = OggPage(in_file)
117
211
  page.serial_no = timestamp
118
212
  page.checksum = page.calc_checksum()
119
- page = prepare_opus_tags(page)
213
+ page = prepare_opus_tags(page, use_custom_tags, bitrate, vbr, opus_binary)
120
214
  page.write_page(out_file, sha)
121
215
  logger.debug("Second page written successfully")
122
216
 
@@ -277,7 +371,8 @@ def fix_tonie_header(out_file, chapters, timestamp, sha):
277
371
 
278
372
 
279
373
  def create_tonie_file(output_file, input_files, no_tonie_header=False, user_timestamp=None,
280
- bitrate=96, vbr=True, ffmpeg_binary=None, opus_binary=None, keep_temp=False, auto_download=False):
374
+ bitrate=96, vbr=True, ffmpeg_binary=None, opus_binary=None, keep_temp=False, auto_download=False,
375
+ use_custom_tags=True):
281
376
  """
282
377
  Create a Tonie file from input files.
283
378
 
@@ -292,6 +387,7 @@ def create_tonie_file(output_file, input_files, no_tonie_header=False, user_time
292
387
  opus_binary: Path to opusenc binary
293
388
  keep_temp: Whether to keep temporary opus files for testing
294
389
  auto_download: Whether to automatically download dependencies if not found
390
+ use_custom_tags: Whether to use dynamic comment tags generated with toniefile_comment_add
295
391
  """
296
392
  from .audio_conversion import get_opus_tempfile
297
393
 
@@ -369,7 +465,7 @@ def create_tonie_file(output_file, input_files, no_tonie_header=False, user_time
369
465
  try:
370
466
  if next_page_no == 2:
371
467
  logger.debug("Processing first file: copying first and second page")
372
- copy_first_and_second_page(handle, out_file, timestamp, sha1)
468
+ copy_first_and_second_page(handle, out_file, timestamp, sha1, use_custom_tags, bitrate, vbr, opus_binary)
373
469
  else:
374
470
  logger.debug("Processing subsequent file: skipping first and second page")
375
471
  other_size = max_size
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TonieToolbox
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Convert audio files to Tonie box compatible format
5
5
  Home-page: https://github.com/Quentendo64/TonieToolbox
6
6
  Author: Quentendo64
@@ -159,15 +159,14 @@ tonietoolbox --recursive --output-to-source "Music/Albums"
159
159
  Run the following command to see all available options:
160
160
 
161
161
  ```
162
- tonietoolbox --help
162
+ tonietoolbox -h
163
163
  ```
164
164
 
165
165
  Output:
166
166
  ```
167
- usage: TonieToolbox.py [-h] [--ts TIMESTAMP] [--ffmpeg FFMPEG] [--opusenc OPUSENC]
168
- [--bitrate BITRATE] [--cbr] [--append-tonie-tag TAG]
169
- [--no-tonie-header] [--info] [--split] [--recursive] [--output-to-source]
170
- [--compare FILE2] [--detailed-compare] [--debug] [--trace] [--quiet] [--silent]
167
+ usage: TonieToolbox.py [-h] [-v] [-t TIMESTAMP] [-f FFMPEG] [-o OPUSENC]
168
+ [-b BITRATE] [-c] [-a TAG] [-n] [-i] [-s] [-r] [-O]
169
+ [-A] [-k] [-C FILE2] [-D] [-d] [-T] [-q] [-Q]
171
170
  SOURCE [TARGET]
172
171
 
173
172
  Create Tonie compatible file from Ogg opus file(s).
@@ -178,25 +177,40 @@ positional arguments:
178
177
 
179
178
  optional arguments:
180
179
  -h, --help show this help message and exit
181
- --ts TIMESTAMP set custom timestamp / bitstream serial / reference .taf file
182
- --ffmpeg FFMPEG specify location of ffmpeg
183
- --opusenc OPUSENC specify location of opusenc
184
- --bitrate BITRATE set encoding bitrate in kbps (default: 96)
185
- --cbr encode in cbr mode
186
- --append-tonie-tag TAG append [TAG] to filename (must be an 8-character hex value)
187
- --no-tonie-header do not write Tonie header
188
- --info Check and display info about Tonie file
189
- --split Split Tonie file into opus tracks
190
- --recursive Process folders recursively
191
- --output-to-source Save output files in the source directory instead of output directory
192
- --compare FILE2 Compare input file with another .taf file for debugging
193
- --detailed-compare Show detailed OGG page differences when comparing files
180
+ -v, --version show program version and exit
181
+ -t, --timestamp TIMESTAMP
182
+ set custom timestamp / bitstream serial / reference .taf file
183
+ -f, --ffmpeg FFMPEG specify location of ffmpeg
184
+ -o, --opusenc OPUSENC specify location of opusenc
185
+ -b, --bitrate BITRATE set encoding bitrate in kbps (default: 96)
186
+ -c, --cbr encode in cbr mode
187
+ -a, --append-tonie-tag TAG
188
+ append [TAG] to filename (must be an 8-character hex value)
189
+ -n, --no-tonie-header do not write Tonie header
190
+ -i, --info Check and display info about Tonie file
191
+ -s, --split Split Tonie file into opus tracks
192
+ -r, --recursive Process folders recursively
193
+ -O, --output-to-source
194
+ Save output files in the source directory instead of output directory
195
+ -A, --auto-download Automatically download FFmpeg and opusenc if needed
196
+ -k, --keep-temp Keep temporary opus files in a temp folder for testing
197
+ -C, --compare FILE2 Compare input file with another .taf file for debugging
198
+ -D, --detailed-compare
199
+ Show detailed OGG page differences when comparing files
200
+
201
+ Version Check Options:
202
+ -S, --skip-update-check
203
+ Skip checking for updates
204
+ -F, --force-refresh-cache
205
+ Force refresh of update information from PyPI
206
+ -X, --clear-version-cache
207
+ Clear cached version information
194
208
 
195
209
  Logging Options:
196
- --debug Enable debug logging
197
- --trace Enable trace logging (very verbose)
198
- --quiet Show only warnings and errors
199
- --silent Show only errors
210
+ -d, --debug Enable debug logging
211
+ -T, --trace Enable trace logging (very verbose)
212
+ -q, --quiet Show only warnings and errors
213
+ -Q, --silent Show only errors
200
214
  ```
201
215
 
202
216
  ### Common Usage Examples
@@ -230,9 +244,9 @@ tonietoolbox file1.taf --compare file2.taf --detailed-compare
230
244
  #### Custom timestamp options:
231
245
 
232
246
  ```
233
- tonietoolbox input.mp3 --ts 1745078762 # UNIX Timestamp
234
- tonietoolbox input.mp3 --ts 0x6803C9EA # Bitstream time
235
- tonietoolbox input.mp3 --ts ./reference.taf # Reference TAF for extraction
247
+ tonietoolbox input.mp3 --timestamp 1745078762 # UNIX Timestamp
248
+ tonietoolbox input.mp3 --timestamp 0x6803C9EA # Bitstream time
249
+ tonietoolbox input.mp3 --timestamp ./reference.taf # Reference TAF for extraction
236
250
  ```
237
251
 
238
252
  #### Set custom bitrate:
@@ -1,21 +1,21 @@
1
- TonieToolbox/__init__.py,sha256=VFFoZT_t4IpL4Df8aABMBjxC8VE2JEKJD6-OHEwd-2A,96
2
- TonieToolbox/__main__.py,sha256=uDWIgVp-8T3jPi9kBDVsOigGoUWSGGeltUyM4zQElb8,10772
1
+ TonieToolbox/__init__.py,sha256=UhSjPdhrXyhaT47L1QQH8FMLyK-1ddkUIQWtXr71Dcs,96
2
+ TonieToolbox/__main__.py,sha256=eumivCJXMmlGZJLk3bC61-NwQEq3x5lElSIsmb2ZKWE,11157
3
3
  TonieToolbox/audio_conversion.py,sha256=ra72qsE8j2GEP_4kqDT9m6aKlnnREZhZAlpf7y83pA0,11202
4
4
  TonieToolbox/constants.py,sha256=QQWQpnCI65GByLlXLOkt2n8nALLu4m6BWp0zuhI3M04,2021
5
- TonieToolbox/dependency_manager.py,sha256=fWtYp_UQDKrgIKcOyy95w7Grk_wYx5Fadyg8ulpb7nE,23451
5
+ TonieToolbox/dependency_manager.py,sha256=fBojtYnzK-jN3zOj9ntwotJhnyJfv6a-iz8zivK6L_Q,25017
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
9
9
  TonieToolbox/opus_packet.py,sha256=OcHXEe3I_K4mWPUD55prpG42sZxJsEeAxqSbFxBmb0c,7895
10
10
  TonieToolbox/recursive_processor.py,sha256=vhQzC05bJVRPX8laj_5lxuRD40eLsZatzwCoCavMsmY,9304
11
- TonieToolbox/tonie_analysis.py,sha256=4eOzxHL_g0TJFhuexNHcZXivxZ7eb5xfb9-efUZ02W0,20344
12
- TonieToolbox/tonie_file.py,sha256=nIS4qhpBKIyPvTU39yYljRidpY6cz78halXlz3HJy9w,15294
11
+ TonieToolbox/tonie_analysis.py,sha256=kp4Wx4cTDddtF2AlS6IX4xs1vQ-mpZ0gsAy4-UdRAAM,23287
12
+ TonieToolbox/tonie_file.py,sha256=vY0s8X4ln35ZXpdpGmBcIxgpTJAjduiVvBh34WObyrw,19647
13
13
  TonieToolbox/tonie_header.proto,sha256=WaWfwO4VrwGtscK2ujfDRKtpeBpaVPoZhI8iMmR-C0U,202
14
14
  TonieToolbox/tonie_header_pb2.py,sha256=s5bp4ULTEekgq6T61z9fDkRavyPM-3eREs20f_Pxxe8,3665
15
15
  TonieToolbox/version_handler.py,sha256=7Zx-pgzAUhz6jMplvNal1wHyxidodVxaNcAV0EMph5k,9778
16
- tonietoolbox-0.2.0.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
17
- tonietoolbox-0.2.0.dist-info/METADATA,sha256=5qQuKTLQ9W3Txo6G_95M33OocNEg52emFXhUZFn4uww,10039
18
- tonietoolbox-0.2.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
19
- tonietoolbox-0.2.0.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
20
- tonietoolbox-0.2.0.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
21
- tonietoolbox-0.2.0.dist-info/RECORD,,
16
+ tonietoolbox-0.2.2.dist-info/licenses/LICENSE.md,sha256=rGoga9ZAgNco9fBapVFpWf6ri7HOBp1KRnt1uIruXMk,35190
17
+ tonietoolbox-0.2.2.dist-info/METADATA,sha256=cm2XH96XGJR6OEL0Wc0yvldIIG0rVFZvhaBheKpuzjw,10514
18
+ tonietoolbox-0.2.2.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
19
+ tonietoolbox-0.2.2.dist-info/entry_points.txt,sha256=oqpeyBxel7aScg35Xr4gZKnf486S5KW9okqeBwyJxxc,60
20
+ tonietoolbox-0.2.2.dist-info/top_level.txt,sha256=Wkkm-2p7I3ENfS7ZbYtYUB2g-xwHrXVlERHfonsOPuE,13
21
+ tonietoolbox-0.2.2.dist-info/RECORD,,