TonieToolbox 0.5.1__py3-none-any.whl → 0.6.0a2__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 +91 -84
- TonieToolbox/artwork.py +12 -7
- TonieToolbox/audio_conversion.py +31 -28
- TonieToolbox/constants.py +110 -9
- TonieToolbox/filename_generator.py +6 -8
- TonieToolbox/integration.py +68 -0
- TonieToolbox/integration_macos.py +477 -0
- TonieToolbox/integration_ubuntu.py +1 -0
- TonieToolbox/integration_windows.py +437 -0
- TonieToolbox/logger.py +8 -10
- TonieToolbox/media_tags.py +17 -97
- TonieToolbox/ogg_page.py +39 -39
- TonieToolbox/opus_packet.py +13 -13
- TonieToolbox/recursive_processor.py +22 -22
- TonieToolbox/tags.py +3 -4
- TonieToolbox/teddycloud.py +50 -50
- TonieToolbox/tonie_analysis.py +24 -23
- TonieToolbox/tonie_file.py +71 -44
- TonieToolbox/tonies_json.py +69 -66
- TonieToolbox/version_handler.py +12 -15
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a2.dist-info}/METADATA +3 -3
- tonietoolbox-0.6.0a2.dist-info/RECORD +30 -0
- tonietoolbox-0.5.1.dist-info/RECORD +0 -26
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a2.dist-info}/WHEEL +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a2.dist-info}/entry_points.txt +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a2.dist-info}/licenses/LICENSE.md +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a2.dist-info}/top_level.txt +0 -0
@@ -14,16 +14,16 @@ from .logger import get_logger
|
|
14
14
|
logger = get_logger('recursive_processor')
|
15
15
|
|
16
16
|
|
17
|
-
def find_audio_folders(root_path: str) ->
|
17
|
+
def find_audio_folders(root_path: str) -> list[dict[str, any]]:
|
18
18
|
"""
|
19
19
|
Find and return all folders that contain audio files in a recursive manner,
|
20
20
|
organized in a way that handles nested folder structures.
|
21
21
|
|
22
22
|
Args:
|
23
|
-
root_path: Root directory to start searching from
|
23
|
+
root_path (str): Root directory to start searching from
|
24
24
|
|
25
25
|
Returns:
|
26
|
-
List of dictionaries with folder information, including paths and relationships
|
26
|
+
list[dict[str, any]]: List of dictionaries with folder information, including paths and relationships
|
27
27
|
"""
|
28
28
|
logger.info("Finding folders with audio files in: %s", root_path)
|
29
29
|
|
@@ -68,15 +68,15 @@ def find_audio_folders(root_path: str) -> List[Dict[str, any]]:
|
|
68
68
|
return folder_list
|
69
69
|
|
70
70
|
|
71
|
-
def determine_processing_folders(folders:
|
71
|
+
def determine_processing_folders(folders: list[dict[str, any]]) -> list[dict[str, any]]:
|
72
72
|
"""
|
73
73
|
Determine which folders should be processed based on their position in the hierarchy.
|
74
74
|
|
75
75
|
Args:
|
76
|
-
folders: List of folder dictionaries with hierarchy information
|
76
|
+
folders (list[dict[str, any]]): List of folder dictionaries with hierarchy information
|
77
77
|
|
78
78
|
Returns:
|
79
|
-
List of folders that should be processed (filtered)
|
79
|
+
list[dict[str, any]]: List of folders that should be processed (filtered)
|
80
80
|
"""
|
81
81
|
# We'll use a set to track which folders we've decided to process
|
82
82
|
to_process = set()
|
@@ -120,15 +120,15 @@ def determine_processing_folders(folders: List[Dict[str, any]]) -> List[Dict[str
|
|
120
120
|
return result
|
121
121
|
|
122
122
|
|
123
|
-
def get_folder_audio_files(folder_path: str) ->
|
123
|
+
def get_folder_audio_files(folder_path: str) -> list[str]:
|
124
124
|
"""
|
125
125
|
Get all audio files in a specific folder.
|
126
126
|
|
127
127
|
Args:
|
128
|
-
folder_path: Path to folder
|
128
|
+
folder_path (str): Path to folder
|
129
129
|
|
130
130
|
Returns:
|
131
|
-
List of paths to audio files in natural sort order
|
131
|
+
list[str]: List of paths to audio files in natural sort order
|
132
132
|
"""
|
133
133
|
audio_files = glob.glob(os.path.join(folder_path, "*"))
|
134
134
|
filtered_files = filter_directories(audio_files)
|
@@ -140,15 +140,15 @@ def get_folder_audio_files(folder_path: str) -> List[str]:
|
|
140
140
|
return sorted_files
|
141
141
|
|
142
142
|
|
143
|
-
def natural_sort(file_list:
|
143
|
+
def natural_sort(file_list: list[str]) -> list[str]:
|
144
144
|
"""
|
145
145
|
Sort a list of files in natural order (so that 2 comes before 10).
|
146
146
|
|
147
147
|
Args:
|
148
|
-
file_list: List of file paths
|
148
|
+
file_list (list[str]): List of file paths
|
149
149
|
|
150
150
|
Returns:
|
151
|
-
Naturally sorted list of file paths
|
151
|
+
list[str]: Naturally sorted list of file paths
|
152
152
|
"""
|
153
153
|
def convert(text):
|
154
154
|
return int(text) if text.isdigit() else text.lower()
|
@@ -159,16 +159,16 @@ def natural_sort(file_list: List[str]) -> List[str]:
|
|
159
159
|
return sorted(file_list, key=alphanum_key)
|
160
160
|
|
161
161
|
|
162
|
-
def extract_folder_meta(folder_path: str) ->
|
162
|
+
def extract_folder_meta(folder_path: str) -> dict[str, str]:
|
163
163
|
"""
|
164
164
|
Extract metadata from folder name.
|
165
165
|
Common format might be: "YYYY - NNN - Title"
|
166
166
|
|
167
167
|
Args:
|
168
|
-
folder_path: Path to folder
|
168
|
+
folder_path (str): Path to folder
|
169
169
|
|
170
170
|
Returns:
|
171
|
-
Dictionary with extracted metadata (year, number, title)
|
171
|
+
dict[str, str]: Dictionary with extracted metadata (year, number, title)
|
172
172
|
"""
|
173
173
|
folder_name = os.path.basename(folder_path)
|
174
174
|
logger.debug("Extracting metadata from folder: %s", folder_name)
|
@@ -210,12 +210,12 @@ def get_folder_name_from_metadata(folder_path: str, use_media_tags: bool = False
|
|
210
210
|
and optionally audio file metadata.
|
211
211
|
|
212
212
|
Args:
|
213
|
-
folder_path: Path to folder
|
214
|
-
use_media_tags: Whether to use media tags from audio files if available
|
215
|
-
template: Optional template for formatting output name using media tags
|
213
|
+
folder_path (str): Path to folder
|
214
|
+
use_media_tags (bool): Whether to use media tags from audio files if available
|
215
|
+
template (str | None): Optional template for formatting output name using media tags
|
216
216
|
|
217
217
|
Returns:
|
218
|
-
String with cleaned output name
|
218
|
+
str: String with cleaned output name
|
219
219
|
"""
|
220
220
|
folder_meta = extract_folder_meta(folder_path)
|
221
221
|
output_name = None
|
@@ -289,17 +289,17 @@ def get_folder_name_from_metadata(folder_path: str, use_media_tags: bool = False
|
|
289
289
|
return output_name
|
290
290
|
|
291
291
|
|
292
|
-
def process_recursive_folders(root_path, use_media_tags=False, name_template=None):
|
292
|
+
def process_recursive_folders(root_path: str, use_media_tags: bool = False, name_template: str = None) -> list[tuple[str, str, list[str]]]:
|
293
293
|
"""
|
294
294
|
Process folders recursively for audio files to create Tonie files.
|
295
295
|
|
296
296
|
Args:
|
297
297
|
root_path (str): The root path to start processing from
|
298
298
|
use_media_tags (bool): Whether to use media tags for naming
|
299
|
-
name_template (str): Template for naming files using media tags
|
299
|
+
name_template (str | None): Template for naming files using media tags
|
300
300
|
|
301
301
|
Returns:
|
302
|
-
list: A list of tuples (output_name, folder_path, audio_files)
|
302
|
+
list[tuple[str, str, list[str]]]: A list of tuples (output_name, folder_path, audio_files)
|
303
303
|
"""
|
304
304
|
logger = get_logger("recursive_processor")
|
305
305
|
logger.info("Processing folders recursively: %s", root_path)
|
TonieToolbox/tags.py
CHANGED
@@ -10,15 +10,14 @@ from typing import Optional, Union
|
|
10
10
|
|
11
11
|
logger = get_logger('tags')
|
12
12
|
|
13
|
-
def get_tags(client: TeddyCloudClient) -> bool:
|
13
|
+
def get_tags(client: 'TeddyCloudClient') -> bool:
|
14
14
|
"""
|
15
15
|
Get and display tags from a TeddyCloud instance.
|
16
16
|
|
17
17
|
Args:
|
18
|
-
client: TeddyCloudClient instance to use for API communication
|
19
|
-
|
18
|
+
client (TeddyCloudClient): TeddyCloudClient instance to use for API communication
|
20
19
|
Returns:
|
21
|
-
True if tags were retrieved successfully, False otherwise
|
20
|
+
bool: True if tags were retrieved successfully, False otherwise
|
22
21
|
"""
|
23
22
|
logger.info("Getting tags from TeddyCloud using provided client")
|
24
23
|
|
TonieToolbox/teddycloud.py
CHANGED
@@ -19,27 +19,33 @@ DEFAULT_RETRY_DELAY = 5 # seconds
|
|
19
19
|
class TeddyCloudClient:
|
20
20
|
"""Client for interacting with TeddyCloud API."""
|
21
21
|
|
22
|
-
def __init__(
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
def __init__(
|
23
|
+
self,
|
24
|
+
base_url: str,
|
25
|
+
ignore_ssl_verify: bool = False,
|
26
|
+
connection_timeout: int = DEFAULT_CONNECTION_TIMEOUT,
|
27
|
+
read_timeout: int = DEFAULT_READ_TIMEOUT,
|
28
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
29
|
+
retry_delay: int = DEFAULT_RETRY_DELAY,
|
30
|
+
username: str = None,
|
31
|
+
password: str = None,
|
32
|
+
cert_file: str = None,
|
33
|
+
key_file: str = None
|
34
|
+
) -> None:
|
29
35
|
"""
|
30
36
|
Initialize the TeddyCloud client.
|
31
37
|
|
32
38
|
Args:
|
33
|
-
base_url: Base URL of the TeddyCloud instance (e.g., https://teddycloud.example.com)
|
34
|
-
ignore_ssl_verify: If True, SSL certificate verification will be disabled (useful for self-signed certificates)
|
35
|
-
connection_timeout: Timeout for establishing a connection
|
36
|
-
read_timeout: Timeout for reading data from the server
|
37
|
-
max_retries: Maximum number of retries for failed requests
|
38
|
-
retry_delay: Delay between retries
|
39
|
-
username: Username for basic authentication (optional)
|
40
|
-
password: Password for basic authentication (optional)
|
41
|
-
cert_file: Path to client certificate file for certificate-based authentication (optional)
|
42
|
-
key_file: Path to client private key file for certificate-based authentication (optional)
|
39
|
+
base_url (str): Base URL of the TeddyCloud instance (e.g., https://teddycloud.example.com)
|
40
|
+
ignore_ssl_verify (bool): If True, SSL certificate verification will be disabled (useful for self-signed certificates)
|
41
|
+
connection_timeout (int): Timeout for establishing a connection
|
42
|
+
read_timeout (int): Timeout for reading data from the server
|
43
|
+
max_retries (int): Maximum number of retries for failed requests
|
44
|
+
retry_delay (int): Delay between retries
|
45
|
+
username (str | None): Username for basic authentication (optional)
|
46
|
+
password (str | None): Password for basic authentication (optional)
|
47
|
+
cert_file (str | None): Path to client certificate file for certificate-based authentication (optional)
|
48
|
+
key_file (str | None): Path to client private key file for certificate-based authentication (optional)
|
43
49
|
"""
|
44
50
|
self.base_url = base_url.rstrip('/')
|
45
51
|
self.ignore_ssl_verify = ignore_ssl_verify
|
@@ -81,7 +87,7 @@ class TeddyCloudClient:
|
|
81
87
|
except ssl.SSLError as e:
|
82
88
|
raise ValueError(f"Failed to load client certificate: {e}")
|
83
89
|
|
84
|
-
def _create_request_kwargs(self):
|
90
|
+
def _create_request_kwargs(self) -> dict:
|
85
91
|
"""
|
86
92
|
Create common request keyword arguments for all API calls.
|
87
93
|
|
@@ -98,18 +104,16 @@ class TeddyCloudClient:
|
|
98
104
|
kwargs['cert'] = self.cert
|
99
105
|
return kwargs
|
100
106
|
|
101
|
-
def _make_request(self, method, endpoint, **kwargs):
|
107
|
+
def _make_request(self, method: str, endpoint: str, **kwargs) -> 'requests.Response':
|
102
108
|
"""
|
103
109
|
Make an HTTP request to the TeddyCloud API with retry logic.
|
104
110
|
|
105
111
|
Args:
|
106
|
-
method: HTTP method (GET, POST, etc.)
|
107
|
-
endpoint: API endpoint (without base URL)
|
112
|
+
method (str): HTTP method (GET, POST, etc.)
|
113
|
+
endpoint (str): API endpoint (without base URL)
|
108
114
|
**kwargs: Additional arguments to pass to requests
|
109
|
-
|
110
115
|
Returns:
|
111
116
|
requests.Response: Response object
|
112
|
-
|
113
117
|
Raises:
|
114
118
|
requests.exceptions.RequestException: If request fails after all retries
|
115
119
|
"""
|
@@ -171,7 +175,7 @@ class TeddyCloudClient:
|
|
171
175
|
|
172
176
|
# ------------- GET API Methods -------------
|
173
177
|
|
174
|
-
def get_tonies_custom_json(self):
|
178
|
+
def get_tonies_custom_json(self) -> dict:
|
175
179
|
"""
|
176
180
|
Get custom Tonies JSON data from the TeddyCloud server.
|
177
181
|
|
@@ -181,7 +185,7 @@ class TeddyCloudClient:
|
|
181
185
|
response = self._make_request('GET', '/api/toniesCustomJson')
|
182
186
|
return response.json()
|
183
187
|
|
184
|
-
def get_tonies_json(self):
|
188
|
+
def get_tonies_json(self) -> dict:
|
185
189
|
"""
|
186
190
|
Get Tonies JSON data from the TeddyCloud server.
|
187
191
|
|
@@ -191,7 +195,7 @@ class TeddyCloudClient:
|
|
191
195
|
response = self._make_request('GET', '/api/toniesJson')
|
192
196
|
return response.json()
|
193
197
|
|
194
|
-
def get_tag_index(self):
|
198
|
+
def get_tag_index(self) -> dict:
|
195
199
|
"""
|
196
200
|
Get tag index data from the TeddyCloud server.
|
197
201
|
|
@@ -201,7 +205,7 @@ class TeddyCloudClient:
|
|
201
205
|
response = self._make_request('GET', '/api/getTagIndex')
|
202
206
|
return response.json()
|
203
207
|
|
204
|
-
def get_file_index(self):
|
208
|
+
def get_file_index(self) -> dict:
|
205
209
|
"""
|
206
210
|
Get file index data from the TeddyCloud server.
|
207
211
|
|
@@ -211,7 +215,7 @@ class TeddyCloudClient:
|
|
211
215
|
response = self._make_request('GET', '/api/fileIndex')
|
212
216
|
return response.json()
|
213
217
|
|
214
|
-
def get_file_index_v2(self):
|
218
|
+
def get_file_index_v2(self) -> dict:
|
215
219
|
"""
|
216
220
|
Get version 2 file index data from the TeddyCloud server.
|
217
221
|
|
@@ -221,7 +225,7 @@ class TeddyCloudClient:
|
|
221
225
|
response = self._make_request('GET', '/api/fileIndexV2')
|
222
226
|
return response.json()
|
223
227
|
|
224
|
-
def get_tonieboxes_json(self):
|
228
|
+
def get_tonieboxes_json(self) -> dict:
|
225
229
|
"""
|
226
230
|
Get Tonieboxes JSON data from the TeddyCloud server.
|
227
231
|
|
@@ -233,15 +237,14 @@ class TeddyCloudClient:
|
|
233
237
|
|
234
238
|
# ------------- POST API Methods -------------
|
235
239
|
|
236
|
-
def create_directory(self, path, overlay=None, special=None):
|
240
|
+
def create_directory(self, path: str, overlay: str = None, special: str = None) -> str:
|
237
241
|
"""
|
238
242
|
Create a directory on the TeddyCloud server.
|
239
243
|
|
240
244
|
Args:
|
241
|
-
path: Directory path to create
|
242
|
-
overlay: Settings overlay ID (optional)
|
243
|
-
special: Special folder source, only 'library' supported yet (optional)
|
244
|
-
|
245
|
+
path (str): Directory path to create
|
246
|
+
overlay (str | None): Settings overlay ID (optional)
|
247
|
+
special (str | None): Special folder source, only 'library' supported yet (optional)
|
245
248
|
Returns:
|
246
249
|
str: Response message from server (usually "OK")
|
247
250
|
"""
|
@@ -254,15 +257,14 @@ class TeddyCloudClient:
|
|
254
257
|
response = self._make_request('POST', '/api/dirCreate', params=params, data=path)
|
255
258
|
return response.text
|
256
259
|
|
257
|
-
def delete_directory(self, path, overlay=None, special=None):
|
260
|
+
def delete_directory(self, path: str, overlay: str = None, special: str = None) -> str:
|
258
261
|
"""
|
259
262
|
Delete a directory from the TeddyCloud server.
|
260
263
|
|
261
264
|
Args:
|
262
|
-
path: Directory path to delete
|
263
|
-
overlay: Settings overlay ID (optional)
|
264
|
-
special: Special folder source, only 'library' supported yet (optional)
|
265
|
-
|
265
|
+
path (str): Directory path to delete
|
266
|
+
overlay (str | None): Settings overlay ID (optional)
|
267
|
+
special (str | None): Special folder source, only 'library' supported yet (optional)
|
266
268
|
Returns:
|
267
269
|
str: Response message from server (usually "OK")
|
268
270
|
"""
|
@@ -275,15 +277,14 @@ class TeddyCloudClient:
|
|
275
277
|
response = self._make_request('POST', '/api/dirDelete', params=params, data=path)
|
276
278
|
return response.text
|
277
279
|
|
278
|
-
def delete_file(self, path, overlay=None, special=None):
|
280
|
+
def delete_file(self, path: str, overlay: str = None, special: str = None) -> str:
|
279
281
|
"""
|
280
282
|
Delete a file from the TeddyCloud server.
|
281
283
|
|
282
284
|
Args:
|
283
|
-
path: File path to delete
|
284
|
-
overlay: Settings overlay ID (optional)
|
285
|
-
special: Special folder source, only 'library' supported yet (optional)
|
286
|
-
|
285
|
+
path (str): File path to delete
|
286
|
+
overlay (str | None): Settings overlay ID (optional)
|
287
|
+
special (str | None): Special folder source, only 'library' supported yet (optional)
|
287
288
|
Returns:
|
288
289
|
str: Response message from server (usually "OK")
|
289
290
|
"""
|
@@ -296,16 +297,15 @@ class TeddyCloudClient:
|
|
296
297
|
response = self._make_request('POST', '/api/fileDelete', params=params, data=path)
|
297
298
|
return response.text
|
298
299
|
|
299
|
-
def upload_file(self, file_path, destination_path=None, overlay=None, special=None):
|
300
|
+
def upload_file(self, file_path: str, destination_path: str = None, overlay: str = None, special: str = None) -> dict:
|
300
301
|
"""
|
301
302
|
Upload a file to the TeddyCloud server.
|
302
303
|
|
303
304
|
Args:
|
304
|
-
file_path: Local path to the file to upload
|
305
|
-
destination_path: Server path where to write the file to (optional)
|
306
|
-
overlay: Settings overlay ID (optional)
|
307
|
-
special: Special folder source, only 'library' supported yet (optional)
|
308
|
-
|
305
|
+
file_path (str): Local path to the file to upload
|
306
|
+
destination_path (str | None): Server path where to write the file to (optional)
|
307
|
+
overlay (str | None): Settings overlay ID (optional)
|
308
|
+
special (str | None): Special folder source, only 'library' supported yet (optional)
|
309
309
|
Returns:
|
310
310
|
dict: JSON response from server
|
311
311
|
"""
|
TonieToolbox/tonie_analysis.py
CHANGED
@@ -11,12 +11,13 @@ from .ogg_page import OggPage
|
|
11
11
|
from .logger import get_logger
|
12
12
|
|
13
13
|
logger = get_logger('tonie_analysis')
|
14
|
-
|
14
|
+
|
15
|
+
def format_time(ts: float) -> str:
|
15
16
|
"""
|
16
17
|
Format a timestamp as a human-readable date and time string.
|
17
18
|
|
18
19
|
Args:
|
19
|
-
ts: Timestamp to format
|
20
|
+
ts (float): Timestamp to format
|
20
21
|
|
21
22
|
Returns:
|
22
23
|
str: Formatted date and time string
|
@@ -24,12 +25,12 @@ def format_time(ts):
|
|
24
25
|
return datetime.datetime.fromtimestamp(ts, datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
|
25
26
|
|
26
27
|
|
27
|
-
def format_hex(data):
|
28
|
+
def format_hex(data: bytes) -> str:
|
28
29
|
"""
|
29
30
|
Format binary data as a hex string.
|
30
31
|
|
31
32
|
Args:
|
32
|
-
data: Binary data to format
|
33
|
+
data (bytes): Binary data to format
|
33
34
|
|
34
35
|
Returns:
|
35
36
|
str: Formatted hex string
|
@@ -37,13 +38,13 @@ def format_hex(data):
|
|
37
38
|
return "".join(format(x, "02X") for x in data)
|
38
39
|
|
39
40
|
|
40
|
-
def granule_to_time_string(granule, sample_rate=1):
|
41
|
+
def granule_to_time_string(granule: int, sample_rate: int = 1) -> str:
|
41
42
|
"""
|
42
43
|
Convert a granule position to a time string.
|
43
44
|
|
44
45
|
Args:
|
45
|
-
granule: Granule position
|
46
|
-
sample_rate: Sample rate in Hz
|
46
|
+
granule (int): Granule position
|
47
|
+
sample_rate (int): Sample rate in Hz
|
47
48
|
|
48
49
|
Returns:
|
49
50
|
str: Formatted time string (HH:MM:SS.FF)
|
@@ -56,7 +57,7 @@ def granule_to_time_string(granule, sample_rate=1):
|
|
56
57
|
return "{:02d}:{:02d}:{:02d}.{:02d}".format(hours, minutes, seconds, fraction)
|
57
58
|
|
58
59
|
|
59
|
-
def get_header_info(in_file):
|
60
|
+
def get_header_info(in_file) -> tuple:
|
60
61
|
"""
|
61
62
|
Get header information from a Tonie file.
|
62
63
|
|
@@ -164,15 +165,15 @@ def get_header_info(in_file):
|
|
164
165
|
)
|
165
166
|
|
166
167
|
|
167
|
-
def get_audio_info(in_file, sample_rate, tonie_header, header_size):
|
168
|
+
def get_audio_info(in_file, sample_rate: int, tonie_header, header_size: int) -> tuple:
|
168
169
|
"""
|
169
170
|
Get audio information from a Tonie file.
|
170
171
|
|
171
172
|
Args:
|
172
173
|
in_file: Input file handle
|
173
|
-
sample_rate: Sample rate in Hz
|
174
|
+
sample_rate (int): Sample rate in Hz
|
174
175
|
tonie_header: Tonie header object
|
175
|
-
header_size: Header size in bytes
|
176
|
+
header_size (int): Header size in bytes
|
176
177
|
|
177
178
|
Returns:
|
178
179
|
tuple: Page count, alignment OK flag, page size OK flag, total time, chapter times
|
@@ -228,12 +229,12 @@ def get_audio_info(in_file, sample_rate, tonie_header, header_size):
|
|
228
229
|
return page_count, alignment_okay, page_size_okay, total_time, chapter_times
|
229
230
|
|
230
231
|
|
231
|
-
def check_tonie_file(filename):
|
232
|
+
def check_tonie_file(filename: str) -> bool:
|
232
233
|
"""
|
233
234
|
Check if a file is a valid Tonie file and display information about it.
|
234
235
|
|
235
236
|
Args:
|
236
|
-
filename: Path to the file to check
|
237
|
+
filename (str): Path to the file to check
|
237
238
|
|
238
239
|
Returns:
|
239
240
|
bool: True if the file is valid, False otherwise
|
@@ -315,13 +316,13 @@ def check_tonie_file(filename):
|
|
315
316
|
return all_ok
|
316
317
|
|
317
318
|
|
318
|
-
def split_to_opus_files(filename, output=None):
|
319
|
+
def split_to_opus_files(filename: str, output: str = None) -> None:
|
319
320
|
"""
|
320
321
|
Split a Tonie file into individual Opus files.
|
321
322
|
|
322
323
|
Args:
|
323
|
-
filename: Path to the Tonie file
|
324
|
-
output: Output directory path (optional)
|
324
|
+
filename (str): Path to the Tonie file
|
325
|
+
output (str | None): Output directory path (optional)
|
325
326
|
"""
|
326
327
|
logger.info("Splitting Tonie file into individual Opus tracks: %s", filename)
|
327
328
|
|
@@ -412,14 +413,14 @@ def split_to_opus_files(filename, output=None):
|
|
412
413
|
logger.info("Successfully split Tonie file into %d individual tracks", len(tonie_header.chapterPages))
|
413
414
|
|
414
415
|
|
415
|
-
def compare_taf_files(file1, file2, detailed=False):
|
416
|
+
def compare_taf_files(file1: str, file2: str, detailed: bool = False) -> bool:
|
416
417
|
"""
|
417
418
|
Compare two .taf files for debugging purposes.
|
418
419
|
|
419
420
|
Args:
|
420
|
-
file1: Path to the first .taf file
|
421
|
-
file2: Path to the second .taf file
|
422
|
-
detailed: Whether to show detailed comparison results
|
421
|
+
file1 (str): Path to the first .taf file
|
422
|
+
file2 (str): Path to the second .taf file
|
423
|
+
detailed (bool): Whether to show detailed comparison results
|
423
424
|
|
424
425
|
Returns:
|
425
426
|
bool: True if files are equivalent, False otherwise
|
@@ -572,7 +573,7 @@ def compare_taf_files(file1, file2, detailed=False):
|
|
572
573
|
logger.info("Files comparison result: Equivalent")
|
573
574
|
return True
|
574
575
|
|
575
|
-
def get_header_info_cli(in_file):
|
576
|
+
def get_header_info_cli(in_file) -> tuple:
|
576
577
|
"""
|
577
578
|
Get header information from a Tonie file.
|
578
579
|
|
@@ -687,12 +688,12 @@ def get_header_info_cli(in_file):
|
|
687
688
|
return (0, tonie_header_pb2.TonieHeader(), 0, 0, None, False, 0, 0, 0, 0, {}, False)
|
688
689
|
|
689
690
|
|
690
|
-
def check_tonie_file_cli(filename):
|
691
|
+
def check_tonie_file_cli(filename: str) -> bool:
|
691
692
|
"""
|
692
693
|
Check if a file is a valid Tonie file
|
693
694
|
|
694
695
|
Args:
|
695
|
-
filename: Path to the file to check
|
696
|
+
filename (str): Path to the file to check
|
696
697
|
|
697
698
|
Returns:
|
698
699
|
bool: True if the file is valid, False otherwise
|