TonieToolbox 0.5.1__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 +85 -84
- TonieToolbox/artwork.py +12 -7
- TonieToolbox/audio_conversion.py +31 -28
- 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 +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.0a1.dist-info}/METADATA +2 -2
- tonietoolbox-0.6.0a1.dist-info/RECORD +31 -0
- tonietoolbox-0.5.1.dist-info/RECORD +0 -26
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a1.dist-info}/WHEEL +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a1.dist-info}/entry_points.txt +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a1.dist-info}/licenses/LICENSE.md +0 -0
- {tonietoolbox-0.5.1.dist-info → tonietoolbox-0.6.0a1.dist-info}/top_level.txt +0 -0
TonieToolbox/ogg_page.py
CHANGED
@@ -18,12 +18,12 @@ from .logger import get_logger
|
|
18
18
|
logger = get_logger('ogg_page')
|
19
19
|
|
20
20
|
|
21
|
-
def create_crc_table():
|
21
|
+
def create_crc_table() -> list[int]:
|
22
22
|
"""
|
23
23
|
Create a CRC lookup table for OGG page checksums.
|
24
24
|
|
25
25
|
Returns:
|
26
|
-
list: CRC32 lookup table for OGG pages
|
26
|
+
list[int]: CRC32 lookup table for OGG pages
|
27
27
|
"""
|
28
28
|
logger.debug("Creating CRC table for OGG page checksums")
|
29
29
|
table = []
|
@@ -39,12 +39,12 @@ def create_crc_table():
|
|
39
39
|
CRC_TABLE = create_crc_table()
|
40
40
|
|
41
41
|
|
42
|
-
def crc32(bytestream):
|
42
|
+
def crc32(bytestream: bytes) -> int:
|
43
43
|
"""
|
44
44
|
Calculate a CRC32 checksum for the given bytestream.
|
45
45
|
|
46
46
|
Args:
|
47
|
-
bytestream: Bytes to calculate the CRC for
|
47
|
+
bytestream (bytes): Bytes to calculate the CRC for
|
48
48
|
|
49
49
|
Returns:
|
50
50
|
int: CRC32 checksum
|
@@ -64,7 +64,7 @@ class OggPage:
|
|
64
64
|
with particular focus on features needed for Tonie compatibility.
|
65
65
|
"""
|
66
66
|
|
67
|
-
def __init__(self, filehandle):
|
67
|
+
def __init__(self, filehandle) -> None:
|
68
68
|
"""
|
69
69
|
Initialize a new OggPage.
|
70
70
|
|
@@ -88,7 +88,7 @@ class OggPage:
|
|
88
88
|
self.parse_header(filehandle)
|
89
89
|
self.parse_segments(filehandle)
|
90
90
|
|
91
|
-
def parse_header(self, filehandle):
|
91
|
+
def parse_header(self, filehandle) -> None:
|
92
92
|
"""
|
93
93
|
Parse the OGG page header.
|
94
94
|
|
@@ -108,7 +108,7 @@ class OggPage:
|
|
108
108
|
logger.trace("Parsed OGG header - Page #%d, Type: %d, Granule: %d, Serial: %d, Segments: %d",
|
109
109
|
self.page_no, self.page_type, self.granule_position, self.serial_no, self.segment_count)
|
110
110
|
|
111
|
-
def parse_segments(self, filehandle):
|
111
|
+
def parse_segments(self, filehandle) -> None:
|
112
112
|
"""
|
113
113
|
Parse the segments in this OGG page.
|
114
114
|
|
@@ -133,12 +133,12 @@ class OggPage:
|
|
133
133
|
logger.error("Found an opus packet spanning OGG pages, which is not supported")
|
134
134
|
raise RuntimeError("Found an opus packet spanning ogg pages. This is not supported yet.")
|
135
135
|
|
136
|
-
def correct_values(self, last_granule):
|
136
|
+
def correct_values(self, last_granule: int) -> None:
|
137
137
|
"""
|
138
138
|
Correct the granule position and checksum for this page.
|
139
139
|
|
140
140
|
Args:
|
141
|
-
last_granule: Last granule position
|
141
|
+
last_granule (int): Last granule position
|
142
142
|
|
143
143
|
Raises:
|
144
144
|
RuntimeError: If there are too many segments in the page
|
@@ -160,7 +160,7 @@ class OggPage:
|
|
160
160
|
logger.trace("Corrected OGG page values: Page #%d, Segments: %d, Granule: %d",
|
161
161
|
self.page_no, self.segment_count, self.granule_position)
|
162
162
|
|
163
|
-
def calc_checksum(self):
|
163
|
+
def calc_checksum(self) -> int:
|
164
164
|
"""
|
165
165
|
Calculate the checksum for this page.
|
166
166
|
|
@@ -178,7 +178,7 @@ class OggPage:
|
|
178
178
|
logger.trace("Calculated checksum for page #%d: 0x%X", self.page_no, checksum)
|
179
179
|
return checksum
|
180
180
|
|
181
|
-
def get_page_size(self):
|
181
|
+
def get_page_size(self) -> int:
|
182
182
|
"""
|
183
183
|
Get the total size of this page in bytes.
|
184
184
|
|
@@ -190,7 +190,7 @@ class OggPage:
|
|
190
190
|
size = size + len(segment.data)
|
191
191
|
return size
|
192
192
|
|
193
|
-
def get_size_of_first_opus_packet(self):
|
193
|
+
def get_size_of_first_opus_packet(self) -> int:
|
194
194
|
"""
|
195
195
|
Get the size of the first opus packet in bytes.
|
196
196
|
|
@@ -208,7 +208,7 @@ class OggPage:
|
|
208
208
|
i = i + 1
|
209
209
|
return size
|
210
210
|
|
211
|
-
def get_segment_count_of_first_opus_packet(self):
|
211
|
+
def get_segment_count_of_first_opus_packet(self) -> int:
|
212
212
|
"""
|
213
213
|
Get the number of segments in the first opus packet.
|
214
214
|
|
@@ -224,14 +224,14 @@ class OggPage:
|
|
224
224
|
count = count + 1
|
225
225
|
return count
|
226
226
|
|
227
|
-
def insert_empty_segment(self, index_after, spanning_packet=False, first_packet=False):
|
227
|
+
def insert_empty_segment(self, index_after: int, spanning_packet: bool = False, first_packet: bool = False) -> None:
|
228
228
|
"""
|
229
229
|
Insert an empty segment after the specified index.
|
230
230
|
|
231
231
|
Args:
|
232
|
-
index_after: Index to insert the segment after
|
233
|
-
spanning_packet: Whether this segment belongs to a packet that spans pages
|
234
|
-
first_packet: Whether this is the first segment of a packet
|
232
|
+
index_after (int): Index to insert the segment after
|
233
|
+
spanning_packet (bool): Whether this segment belongs to a packet that spans pages
|
234
|
+
first_packet (bool): Whether this is the first segment of a packet
|
235
235
|
"""
|
236
236
|
logger.trace("Inserting empty segment after index %d (spanning: %s, first: %s)",
|
237
237
|
index_after, spanning_packet, first_packet)
|
@@ -242,12 +242,12 @@ class OggPage:
|
|
242
242
|
segment.data = bytes()
|
243
243
|
self.segments.insert(index_after + 1, segment)
|
244
244
|
|
245
|
-
def get_opus_packet_size(self, seg_start):
|
245
|
+
def get_opus_packet_size(self, seg_start: int) -> int:
|
246
246
|
"""
|
247
247
|
Get the size of the opus packet starting at the specified segment index.
|
248
248
|
|
249
249
|
Args:
|
250
|
-
seg_start: Starting segment index
|
250
|
+
seg_start (int): Starting segment index
|
251
251
|
|
252
252
|
Returns:
|
253
253
|
int: Size of the opus packet in bytes
|
@@ -259,12 +259,12 @@ class OggPage:
|
|
259
259
|
seg_start = seg_start + 1
|
260
260
|
return size
|
261
261
|
|
262
|
-
def get_segment_count_of_packet_at(self, seg_start):
|
262
|
+
def get_segment_count_of_packet_at(self, seg_start: int) -> int:
|
263
263
|
"""
|
264
264
|
Get the number of segments in the packet starting at the specified segment index.
|
265
265
|
|
266
266
|
Args:
|
267
|
-
seg_start: Starting segment index
|
267
|
+
seg_start (int): Starting segment index
|
268
268
|
|
269
269
|
Returns:
|
270
270
|
int: Number of segments
|
@@ -274,13 +274,13 @@ class OggPage:
|
|
274
274
|
seg_end = seg_end + 1
|
275
275
|
return seg_end - seg_start
|
276
276
|
|
277
|
-
def redistribute_packet_data_at(self, seg_start, pad_count):
|
277
|
+
def redistribute_packet_data_at(self, seg_start: int, pad_count: int) -> None:
|
278
278
|
"""
|
279
279
|
Redistribute packet data starting at the specified segment index.
|
280
280
|
|
281
281
|
Args:
|
282
|
-
seg_start: Starting segment index
|
283
|
-
pad_count: Number of padding bytes to add
|
282
|
+
seg_start (int): Starting segment index
|
283
|
+
pad_count (int): Number of padding bytes to add
|
284
284
|
"""
|
285
285
|
logger.trace("Redistributing packet data at segment %d with %d padding bytes",
|
286
286
|
seg_start, pad_count)
|
@@ -316,14 +316,14 @@ class OggPage:
|
|
316
316
|
logger.trace("Redistribution complete, %d segments used", seg_count)
|
317
317
|
assert len(full_data) == 0
|
318
318
|
|
319
|
-
def convert_packet_to_framepacking_three_and_pad(self, seg_start, pad=False, count=0):
|
319
|
+
def convert_packet_to_framepacking_three_and_pad(self, seg_start: int, pad: bool = False, count: int = 0) -> None:
|
320
320
|
"""
|
321
321
|
Convert the packet to framepacking three mode and add padding if required.
|
322
322
|
|
323
323
|
Args:
|
324
|
-
seg_start: Starting segment index
|
325
|
-
pad: Whether to add padding
|
326
|
-
count: Number of padding bytes to add
|
324
|
+
seg_start (int): Starting segment index
|
325
|
+
pad (bool): Whether to add padding
|
326
|
+
count (int): Number of padding bytes to add
|
327
327
|
|
328
328
|
Raises:
|
329
329
|
AssertionError: If the segment is not the first packet
|
@@ -336,13 +336,13 @@ class OggPage:
|
|
336
336
|
self.segments[seg_start].set_pad_count(count)
|
337
337
|
self.redistribute_packet_data_at(seg_start, count)
|
338
338
|
|
339
|
-
def calc_actual_padding_value(self, seg_start, bytes_needed):
|
339
|
+
def calc_actual_padding_value(self, seg_start: int, bytes_needed: int) -> int:
|
340
340
|
"""
|
341
341
|
Calculate the actual padding value needed for the packet.
|
342
342
|
|
343
343
|
Args:
|
344
|
-
seg_start: Starting segment index
|
345
|
-
bytes_needed: Number of bytes needed for padding
|
344
|
+
seg_start (int): Starting segment index
|
345
|
+
bytes_needed (int): Number of bytes needed for padding
|
346
346
|
|
347
347
|
Returns:
|
348
348
|
int: Actual padding value or a special return code
|
@@ -426,13 +426,13 @@ class OggPage:
|
|
426
426
|
logger.trace("Calculated actual padding value: %d", result)
|
427
427
|
return result
|
428
428
|
|
429
|
-
def pad(self, pad_to, idx_offset
|
429
|
+
def pad(self, pad_to: int, idx_offset: int = -1) -> None:
|
430
430
|
"""
|
431
431
|
Pad the page to the specified size.
|
432
432
|
|
433
433
|
Args:
|
434
|
-
pad_to: Target size to pad to
|
435
|
-
idx_offset: Index offset to start from, defaults to last segment
|
434
|
+
pad_to (int): Target size to pad to
|
435
|
+
idx_offset (int): Index offset to start from, defaults to last segment
|
436
436
|
|
437
437
|
Raises:
|
438
438
|
RuntimeError: If beginning of last packet cannot be found
|
@@ -490,7 +490,7 @@ class OggPage:
|
|
490
490
|
final_size, pad_to)
|
491
491
|
assert final_size == pad_to
|
492
492
|
|
493
|
-
def pad_one_byte(self):
|
493
|
+
def pad_one_byte(self) -> None:
|
494
494
|
"""
|
495
495
|
Add one byte of padding to the page.
|
496
496
|
|
@@ -515,7 +515,7 @@ class OggPage:
|
|
515
515
|
logger.trace("Converting packet to framepacking 3")
|
516
516
|
self.convert_packet_to_framepacking_three_and_pad(i)
|
517
517
|
|
518
|
-
def write_page(self, filehandle, sha1=None):
|
518
|
+
def write_page(self, filehandle, sha1=None) -> None:
|
519
519
|
"""
|
520
520
|
Write the page to a file handle.
|
521
521
|
|
@@ -537,12 +537,12 @@ class OggPage:
|
|
537
537
|
segment.write(filehandle)
|
538
538
|
|
539
539
|
@staticmethod
|
540
|
-
def from_page(other_page):
|
540
|
+
def from_page(other_page: 'OggPage') -> 'OggPage':
|
541
541
|
"""
|
542
542
|
Create a new OggPage based on another page.
|
543
543
|
|
544
544
|
Args:
|
545
|
-
other_page: Source page to copy from
|
545
|
+
other_page (OggPage): Source page to copy from
|
546
546
|
|
547
547
|
Returns:
|
548
548
|
OggPage: New page with copied properties
|
@@ -560,7 +560,7 @@ class OggPage:
|
|
560
560
|
return new_page
|
561
561
|
|
562
562
|
@staticmethod
|
563
|
-
def seek_to_page_header(filehandle):
|
563
|
+
def seek_to_page_header(filehandle) -> bool:
|
564
564
|
"""
|
565
565
|
Seek to the next OGG page header in a file.
|
566
566
|
|
TonieToolbox/opus_packet.py
CHANGED
@@ -18,15 +18,15 @@ class OpusPacket:
|
|
18
18
|
with particular focus on features needed for Tonie compatibility.
|
19
19
|
"""
|
20
20
|
|
21
|
-
def __init__(self, filehandle, size
|
21
|
+
def __init__(self, filehandle, size: int = -1, last_size: int = -1, dont_parse_info: bool = False) -> None:
|
22
22
|
"""
|
23
23
|
Initialize a new OpusPacket.
|
24
24
|
|
25
25
|
Args:
|
26
26
|
filehandle: File handle to read the packet data from, or None to create an empty packet
|
27
|
-
size: Size of the packet in bytes
|
28
|
-
last_size: Size of the previous packet in bytes
|
29
|
-
dont_parse_info: If True, don't parse the packet information even if this is a first packet
|
27
|
+
size (int): Size of the packet in bytes
|
28
|
+
last_size (int): Size of the previous packet in bytes
|
29
|
+
dont_parse_info (bool): If True, don't parse the packet information even if this is a first packet
|
30
30
|
"""
|
31
31
|
self.config_value = None
|
32
32
|
self.stereo = None
|
@@ -51,7 +51,7 @@ class OpusPacket:
|
|
51
51
|
if self.first_packet and not dont_parse_info:
|
52
52
|
self.parse_segment_info()
|
53
53
|
|
54
|
-
def get_frame_count(self):
|
54
|
+
def get_frame_count(self) -> int:
|
55
55
|
"""
|
56
56
|
Get the number of frames in this packet based on its framepacking.
|
57
57
|
|
@@ -68,7 +68,7 @@ class OpusPacket:
|
|
68
68
|
unpacked = struct.unpack("<B", self.data[1:2])
|
69
69
|
return unpacked[0] & 63
|
70
70
|
|
71
|
-
def get_padding(self):
|
71
|
+
def get_padding(self) -> int:
|
72
72
|
"""
|
73
73
|
Get the padding count for this packet.
|
74
74
|
|
@@ -94,7 +94,7 @@ class OpusPacket:
|
|
94
94
|
logger.trace("Packet has %d bytes of padding", total_padding)
|
95
95
|
return total_padding
|
96
96
|
|
97
|
-
def get_frame_size(self):
|
97
|
+
def get_frame_size(self) -> float:
|
98
98
|
"""
|
99
99
|
Get the frame size in milliseconds based on the config value.
|
100
100
|
|
@@ -121,7 +121,7 @@ class OpusPacket:
|
|
121
121
|
logger.error(error_msg)
|
122
122
|
raise RuntimeError(error_msg)
|
123
123
|
|
124
|
-
def calc_granule(self):
|
124
|
+
def calc_granule(self) -> float:
|
125
125
|
"""
|
126
126
|
Calculate the granule position for this packet.
|
127
127
|
|
@@ -133,7 +133,7 @@ class OpusPacket:
|
|
133
133
|
granule, self.frame_size, self.frame_count)
|
134
134
|
return granule
|
135
135
|
|
136
|
-
def parse_segment_info(self):
|
136
|
+
def parse_segment_info(self) -> None:
|
137
137
|
"""Parse the segment information from the packet data."""
|
138
138
|
logger.trace("Parsing segment info from packet data")
|
139
139
|
byte = struct.unpack("<B", self.data[0:1])[0]
|
@@ -148,7 +148,7 @@ class OpusPacket:
|
|
148
148
|
logger.trace("Packet info: config=%d, stereo=%d, framepacking=%d, frame_count=%d, frame_size=%f",
|
149
149
|
self.config_value, self.stereo, self.framepacking, self.frame_count, self.frame_size)
|
150
150
|
|
151
|
-
def write(self, filehandle):
|
151
|
+
def write(self, filehandle) -> None:
|
152
152
|
"""
|
153
153
|
Write the packet data to a file.
|
154
154
|
|
@@ -159,7 +159,7 @@ class OpusPacket:
|
|
159
159
|
logger.trace("Writing %d bytes of packet data to file", len(self.data))
|
160
160
|
filehandle.write(self.data)
|
161
161
|
|
162
|
-
def convert_to_framepacking_three(self):
|
162
|
+
def convert_to_framepacking_three(self) -> None:
|
163
163
|
"""
|
164
164
|
Convert the packet to use framepacking mode 3.
|
165
165
|
|
@@ -182,12 +182,12 @@ class OpusPacket:
|
|
182
182
|
self.framepacking = 3
|
183
183
|
logger.debug("Packet successfully converted to framepacking mode 3")
|
184
184
|
|
185
|
-
def set_pad_count(self, count):
|
185
|
+
def set_pad_count(self, count: int) -> None:
|
186
186
|
"""
|
187
187
|
Set the padding count for this packet.
|
188
188
|
|
189
189
|
Args:
|
190
|
-
count: Number of padding bytes to add
|
190
|
+
count (int): Number of padding bytes to add
|
191
191
|
|
192
192
|
Raises:
|
193
193
|
AssertionError: If the packet is not using framepacking mode 3 or is already padded
|
@@ -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
|
|