TonieToolbox 0.1.0__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 +5 -0
- TonieToolbox/__main__.py +145 -0
- TonieToolbox/audio_conversion.py +194 -0
- TonieToolbox/constants.py +14 -0
- TonieToolbox/dependency_manager.py +378 -0
- TonieToolbox/filename_generator.py +94 -0
- TonieToolbox/logger.py +57 -0
- TonieToolbox/ogg_page.py +588 -0
- TonieToolbox/opus_packet.py +219 -0
- TonieToolbox/tonie_analysis.py +522 -0
- TonieToolbox/tonie_file.py +411 -0
- TonieToolbox/tonie_header.proto +11 -0
- TonieToolbox/tonie_header_pb2.py +99 -0
- tonietoolbox-0.1.0.dist-info/METADATA +301 -0
- tonietoolbox-0.1.0.dist-info/RECORD +19 -0
- tonietoolbox-0.1.0.dist-info/WHEEL +5 -0
- tonietoolbox-0.1.0.dist-info/entry_points.txt +2 -0
- tonietoolbox-0.1.0.dist-info/licenses/LICENSE.md +674 -0
- tonietoolbox-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,411 @@
|
|
1
|
+
"""
|
2
|
+
Tonie file operations module
|
3
|
+
"""
|
4
|
+
|
5
|
+
import datetime
|
6
|
+
import hashlib
|
7
|
+
import math
|
8
|
+
import struct
|
9
|
+
import time
|
10
|
+
import os
|
11
|
+
|
12
|
+
from . import tonie_header_pb2
|
13
|
+
from .opus_packet import OpusPacket
|
14
|
+
from .ogg_page import OggPage
|
15
|
+
from .constants import OPUS_TAGS, SAMPLE_RATE_KHZ
|
16
|
+
from .logger import get_logger
|
17
|
+
|
18
|
+
# Setup logging
|
19
|
+
logger = get_logger('tonie_file')
|
20
|
+
|
21
|
+
|
22
|
+
def check_identification_header(page):
|
23
|
+
"""
|
24
|
+
Check if a page contains a valid Opus identification header.
|
25
|
+
|
26
|
+
Args:
|
27
|
+
page: OggPage to check
|
28
|
+
|
29
|
+
Raises:
|
30
|
+
AssertionError: If the header is invalid or unsupported
|
31
|
+
"""
|
32
|
+
segment = page.segments[0]
|
33
|
+
unpacked = struct.unpack("<8sBBHLH", segment.data[0:18])
|
34
|
+
logger.debug("Checking Opus identification header")
|
35
|
+
|
36
|
+
if unpacked[0] != b"OpusHead":
|
37
|
+
logger.error("Invalid opus file: OpusHead signature not found")
|
38
|
+
assert unpacked[0] == b"OpusHead", "Invalid opus file?"
|
39
|
+
|
40
|
+
if unpacked[1] != 1:
|
41
|
+
logger.error("Invalid opus file: Version mismatch")
|
42
|
+
assert unpacked[1] == 1, "Invalid opus file?"
|
43
|
+
|
44
|
+
if unpacked[2] != 2:
|
45
|
+
logger.error("Only stereo tracks are supported, found channel count: %d", unpacked[2])
|
46
|
+
assert unpacked[2] == 2, "Only stereo tracks are supported"
|
47
|
+
|
48
|
+
if unpacked[4] != SAMPLE_RATE_KHZ * 1000:
|
49
|
+
logger.error("Sample rate needs to be 48 kHz, found: %d Hz", unpacked[4])
|
50
|
+
assert unpacked[4] == SAMPLE_RATE_KHZ * 1000, "Sample rate needs to be 48 kHz"
|
51
|
+
|
52
|
+
logger.debug("Opus identification header is valid")
|
53
|
+
|
54
|
+
|
55
|
+
def prepare_opus_tags(page):
|
56
|
+
"""
|
57
|
+
Prepare standard Opus tags for a Tonie file.
|
58
|
+
|
59
|
+
Args:
|
60
|
+
page: OggPage to modify
|
61
|
+
|
62
|
+
Returns:
|
63
|
+
OggPage: Modified page with Tonie-compatible Opus tags
|
64
|
+
"""
|
65
|
+
logger.debug("Preparing Opus tags for Tonie compatibility")
|
66
|
+
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)
|
80
|
+
page.correct_values(0)
|
81
|
+
logger.trace("Opus tags prepared with %d segments", len(page.segments))
|
82
|
+
return page
|
83
|
+
|
84
|
+
|
85
|
+
def copy_first_and_second_page(in_file, out_file, timestamp, sha):
|
86
|
+
"""
|
87
|
+
Copy and modify the first two pages of an Opus file for a Tonie file.
|
88
|
+
|
89
|
+
Args:
|
90
|
+
in_file: Input file handle
|
91
|
+
out_file: Output file handle
|
92
|
+
timestamp: Timestamp to use for the Tonie file
|
93
|
+
sha: SHA1 hash object to update with written data
|
94
|
+
|
95
|
+
Raises:
|
96
|
+
RuntimeError: If OGG pages cannot be found
|
97
|
+
"""
|
98
|
+
logger.debug("Copying first and second pages with timestamp %d", timestamp)
|
99
|
+
found = OggPage.seek_to_page_header(in_file)
|
100
|
+
if not found:
|
101
|
+
logger.error("First OGG page not found in input file")
|
102
|
+
raise RuntimeError("First ogg page not found")
|
103
|
+
|
104
|
+
page = OggPage(in_file)
|
105
|
+
page.serial_no = timestamp
|
106
|
+
page.checksum = page.calc_checksum()
|
107
|
+
check_identification_header(page)
|
108
|
+
page.write_page(out_file, sha)
|
109
|
+
logger.debug("First page written successfully")
|
110
|
+
|
111
|
+
found = OggPage.seek_to_page_header(in_file)
|
112
|
+
if not found:
|
113
|
+
logger.error("Second OGG page not found in input file")
|
114
|
+
raise RuntimeError("Second ogg page not found")
|
115
|
+
|
116
|
+
page = OggPage(in_file)
|
117
|
+
page.serial_no = timestamp
|
118
|
+
page.checksum = page.calc_checksum()
|
119
|
+
page = prepare_opus_tags(page)
|
120
|
+
page.write_page(out_file, sha)
|
121
|
+
logger.debug("Second page written successfully")
|
122
|
+
|
123
|
+
|
124
|
+
def skip_first_two_pages(in_file):
|
125
|
+
"""
|
126
|
+
Skip the first two pages of an Opus file.
|
127
|
+
|
128
|
+
Args:
|
129
|
+
in_file: Input file handle
|
130
|
+
|
131
|
+
Raises:
|
132
|
+
RuntimeError: If OGG pages cannot be found
|
133
|
+
"""
|
134
|
+
logger.debug("Skipping first two pages")
|
135
|
+
found = OggPage.seek_to_page_header(in_file)
|
136
|
+
if not found:
|
137
|
+
logger.error("First OGG page not found in input file")
|
138
|
+
raise RuntimeError("First ogg page not found")
|
139
|
+
|
140
|
+
page = OggPage(in_file)
|
141
|
+
check_identification_header(page)
|
142
|
+
|
143
|
+
found = OggPage.seek_to_page_header(in_file)
|
144
|
+
if not found:
|
145
|
+
logger.error("Second OGG page not found in input file")
|
146
|
+
raise RuntimeError("Second ogg page not found")
|
147
|
+
|
148
|
+
OggPage(in_file)
|
149
|
+
logger.debug("First two pages skipped successfully")
|
150
|
+
|
151
|
+
|
152
|
+
def read_all_remaining_pages(in_file):
|
153
|
+
"""
|
154
|
+
Read all remaining OGG pages from an input file.
|
155
|
+
|
156
|
+
Args:
|
157
|
+
in_file: Input file handle
|
158
|
+
|
159
|
+
Returns:
|
160
|
+
list: List of OggPage objects
|
161
|
+
"""
|
162
|
+
logger.debug("Reading all remaining OGG pages")
|
163
|
+
remaining_pages = []
|
164
|
+
|
165
|
+
found = OggPage.seek_to_page_header(in_file)
|
166
|
+
page_count = 0
|
167
|
+
|
168
|
+
while found:
|
169
|
+
remaining_pages.append(OggPage(in_file))
|
170
|
+
page_count += 1
|
171
|
+
found = OggPage.seek_to_page_header(in_file)
|
172
|
+
|
173
|
+
logger.debug("Read %d remaining OGG pages", page_count)
|
174
|
+
return remaining_pages
|
175
|
+
|
176
|
+
|
177
|
+
def resize_pages(old_pages, max_page_size, first_page_size, template_page, last_granule=0, start_no=2,
|
178
|
+
set_last_page_flag=False):
|
179
|
+
"""
|
180
|
+
Resize OGG pages to fit Tonie requirements.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
old_pages: List of original OggPage objects
|
184
|
+
max_page_size: Maximum size for pages
|
185
|
+
first_page_size: Size for the first page
|
186
|
+
template_page: Template OggPage to use for creating new pages
|
187
|
+
last_granule: Last granule position
|
188
|
+
start_no: Starting page number
|
189
|
+
set_last_page_flag: Whether to set the last page flag
|
190
|
+
|
191
|
+
Returns:
|
192
|
+
list: List of resized OggPage objects
|
193
|
+
"""
|
194
|
+
logger.debug("Resizing %d OGG pages (max_size=%d, first_size=%d, start_no=%d)",
|
195
|
+
len(old_pages), max_page_size, first_page_size, start_no)
|
196
|
+
|
197
|
+
new_pages = []
|
198
|
+
page = None
|
199
|
+
page_no = start_no
|
200
|
+
max_size = first_page_size
|
201
|
+
|
202
|
+
new_page = OggPage.from_page(template_page)
|
203
|
+
new_page.page_no = page_no
|
204
|
+
|
205
|
+
while len(old_pages) or not (page is None):
|
206
|
+
if page is None:
|
207
|
+
page = old_pages.pop(0)
|
208
|
+
|
209
|
+
size = page.get_size_of_first_opus_packet()
|
210
|
+
seg_count = page.get_segment_count_of_first_opus_packet()
|
211
|
+
|
212
|
+
if (size + seg_count + new_page.get_page_size() <= max_size) and (len(new_page.segments) + seg_count < 256):
|
213
|
+
for i in range(seg_count):
|
214
|
+
new_page.segments.append(page.segments.pop(0))
|
215
|
+
if not len(page.segments):
|
216
|
+
page = None
|
217
|
+
else:
|
218
|
+
new_page.pad(max_size)
|
219
|
+
new_page.correct_values(last_granule)
|
220
|
+
last_granule = new_page.granule_position
|
221
|
+
new_pages.append(new_page)
|
222
|
+
logger.trace("Created new page #%d with %d segments", page_no, len(new_page.segments))
|
223
|
+
|
224
|
+
new_page = OggPage.from_page(template_page)
|
225
|
+
page_no = page_no + 1
|
226
|
+
new_page.page_no = page_no
|
227
|
+
max_size = max_page_size
|
228
|
+
|
229
|
+
if len(new_page.segments):
|
230
|
+
if set_last_page_flag:
|
231
|
+
new_page.page_type = 4
|
232
|
+
logger.debug("Setting last page flag on page #%d", page_no)
|
233
|
+
|
234
|
+
new_page.pad(max_size)
|
235
|
+
new_page.correct_values(last_granule)
|
236
|
+
new_pages.append(new_page)
|
237
|
+
logger.trace("Created final page #%d with %d segments", page_no, len(new_page.segments))
|
238
|
+
|
239
|
+
logger.debug("Resized to %d OGG pages", len(new_pages))
|
240
|
+
return new_pages
|
241
|
+
|
242
|
+
|
243
|
+
def fix_tonie_header(out_file, chapters, timestamp, sha):
|
244
|
+
"""
|
245
|
+
Fix the Tonie header in a file.
|
246
|
+
|
247
|
+
Args:
|
248
|
+
out_file: Output file handle
|
249
|
+
chapters: List of chapter page numbers
|
250
|
+
timestamp: Timestamp for the Tonie file
|
251
|
+
sha: SHA1 hash object with file content
|
252
|
+
"""
|
253
|
+
logger.info("Writing Tonie header with %d chapters and timestamp %d", len(chapters), timestamp)
|
254
|
+
tonie_header = tonie_header_pb2.TonieHeader()
|
255
|
+
|
256
|
+
tonie_header.dataHash = sha.digest()
|
257
|
+
data_length = out_file.seek(0, 1) - 0x1000
|
258
|
+
tonie_header.dataLength = data_length
|
259
|
+
tonie_header.timestamp = timestamp
|
260
|
+
logger.debug("Data length: %d bytes, SHA1: %s", data_length, sha.hexdigest())
|
261
|
+
|
262
|
+
for chapter in chapters:
|
263
|
+
tonie_header.chapterPages.append(chapter)
|
264
|
+
logger.trace("Added chapter at page %d", chapter)
|
265
|
+
|
266
|
+
tonie_header.padding = bytes(0x100)
|
267
|
+
|
268
|
+
header = tonie_header.SerializeToString()
|
269
|
+
pad = 0xFFC - len(header) + 0x100
|
270
|
+
tonie_header.padding = bytes(pad)
|
271
|
+
header = tonie_header.SerializeToString()
|
272
|
+
|
273
|
+
out_file.seek(0)
|
274
|
+
out_file.write(struct.pack(">L", len(header)))
|
275
|
+
out_file.write(header)
|
276
|
+
logger.debug("Tonie header written successfully (size: %d bytes)", len(header))
|
277
|
+
|
278
|
+
|
279
|
+
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):
|
281
|
+
"""
|
282
|
+
Create a Tonie file from input files.
|
283
|
+
|
284
|
+
Args:
|
285
|
+
output_file: Output file path
|
286
|
+
input_files: List of input file paths
|
287
|
+
no_tonie_header: Whether to omit the Tonie header
|
288
|
+
user_timestamp: Custom timestamp to use
|
289
|
+
bitrate: Bitrate for encoding in kbps
|
290
|
+
vbr: Whether to use variable bitrate encoding (True) or constant (False)
|
291
|
+
ffmpeg_binary: Path to ffmpeg binary
|
292
|
+
opus_binary: Path to opusenc binary
|
293
|
+
keep_temp: Whether to keep temporary opus files for testing
|
294
|
+
"""
|
295
|
+
from .audio_conversion import get_opus_tempfile
|
296
|
+
|
297
|
+
logger.info("Creating Tonie file from %d input files", len(input_files))
|
298
|
+
logger.debug("Output file: %s, Bitrate: %d kbps, VBR: %s, No header: %s",
|
299
|
+
output_file, bitrate, vbr, no_tonie_header)
|
300
|
+
|
301
|
+
temp_files = [] # Keep track of temporary files created
|
302
|
+
|
303
|
+
with open(output_file, "wb") as out_file:
|
304
|
+
if not no_tonie_header:
|
305
|
+
logger.debug("Reserving space for Tonie header (0x1000 bytes)")
|
306
|
+
out_file.write(bytearray(0x1000))
|
307
|
+
|
308
|
+
if user_timestamp is not None:
|
309
|
+
if os.path.isfile(user_timestamp) and user_timestamp.lower().endswith('.taf'):
|
310
|
+
logger.debug("Extracting timestamp from Tonie file: %s", user_timestamp)
|
311
|
+
from .tonie_analysis import get_header_info
|
312
|
+
try:
|
313
|
+
with open(user_timestamp, "rb") as taf_file:
|
314
|
+
_, tonie_header, _, _, _, _, _, _, _, bitstream_serial_no = get_header_info(taf_file)
|
315
|
+
timestamp = bitstream_serial_no
|
316
|
+
logger.debug("Extracted timestamp from Tonie file: %d", timestamp)
|
317
|
+
except Exception as e:
|
318
|
+
logger.error("Failed to extract timestamp from Tonie file: %s", str(e))
|
319
|
+
timestamp = int(time.time())
|
320
|
+
logger.debug("Falling back to current timestamp: %d", timestamp)
|
321
|
+
elif user_timestamp.startswith("0x"):
|
322
|
+
timestamp = int(user_timestamp, 16)
|
323
|
+
logger.debug("Using user-provided hexadecimal timestamp: %d", timestamp)
|
324
|
+
else:
|
325
|
+
try:
|
326
|
+
timestamp = int(user_timestamp)
|
327
|
+
logger.debug("Using user-provided decimal timestamp: %d", timestamp)
|
328
|
+
except ValueError:
|
329
|
+
logger.error("Invalid timestamp format: %s", user_timestamp)
|
330
|
+
timestamp = int(time.time())
|
331
|
+
logger.debug("Falling back to current timestamp: %d", timestamp)
|
332
|
+
else:
|
333
|
+
timestamp = int(time.time())
|
334
|
+
logger.debug("Using current timestamp: %d", timestamp)
|
335
|
+
|
336
|
+
sha1 = hashlib.sha1()
|
337
|
+
|
338
|
+
template_page = None
|
339
|
+
chapters = []
|
340
|
+
total_granule = 0
|
341
|
+
next_page_no = 2
|
342
|
+
max_size = 0x1000
|
343
|
+
other_size = 0xE00
|
344
|
+
last_track = False
|
345
|
+
|
346
|
+
pad_len = math.ceil(math.log(len(input_files) + 1, 10))
|
347
|
+
format_string = "[{{:0{}d}}/{:0{}d}] {{}}".format(pad_len, len(input_files), pad_len)
|
348
|
+
|
349
|
+
for index in range(len(input_files)):
|
350
|
+
fname = input_files[index]
|
351
|
+
logger.info(format_string.format(index + 1, fname))
|
352
|
+
if index == len(input_files) - 1:
|
353
|
+
last_track = True
|
354
|
+
logger.debug("Processing last track")
|
355
|
+
|
356
|
+
if fname.lower().endswith(".opus"):
|
357
|
+
logger.debug("Input is already in Opus format")
|
358
|
+
handle = open(fname, "rb")
|
359
|
+
temp_file_path = None
|
360
|
+
else:
|
361
|
+
logger.debug("Converting %s to Opus format (bitrate: %d kbps, VBR: %s)",
|
362
|
+
fname, bitrate, vbr)
|
363
|
+
handle, temp_file_path = get_opus_tempfile(ffmpeg_binary, opus_binary, fname, bitrate, vbr, keep_temp)
|
364
|
+
if temp_file_path:
|
365
|
+
temp_files.append(temp_file_path)
|
366
|
+
logger.debug("Temporary opus file saved to: %s", temp_file_path)
|
367
|
+
|
368
|
+
try:
|
369
|
+
if next_page_no == 2:
|
370
|
+
logger.debug("Processing first file: copying first and second page")
|
371
|
+
copy_first_and_second_page(handle, out_file, timestamp, sha1)
|
372
|
+
else:
|
373
|
+
logger.debug("Processing subsequent file: skipping first and second page")
|
374
|
+
other_size = max_size
|
375
|
+
skip_first_two_pages(handle)
|
376
|
+
|
377
|
+
logger.debug("Reading remaining pages from file")
|
378
|
+
pages = read_all_remaining_pages(handle)
|
379
|
+
|
380
|
+
if template_page is None:
|
381
|
+
template_page = OggPage.from_page(pages[0])
|
382
|
+
template_page.serial_no = timestamp
|
383
|
+
logger.debug("Created template page with serial no %d", timestamp)
|
384
|
+
|
385
|
+
if next_page_no == 2:
|
386
|
+
chapters.append(0)
|
387
|
+
logger.debug("Added first chapter at page 0")
|
388
|
+
else:
|
389
|
+
chapters.append(next_page_no)
|
390
|
+
logger.debug("Added chapter at page %d", next_page_no)
|
391
|
+
|
392
|
+
logger.debug("Resizing pages for track %d", index + 1)
|
393
|
+
new_pages = resize_pages(pages, max_size, other_size, template_page,
|
394
|
+
total_granule, next_page_no, last_track)
|
395
|
+
|
396
|
+
for new_page in new_pages:
|
397
|
+
new_page.write_page(out_file, sha1)
|
398
|
+
|
399
|
+
last_page = new_pages[len(new_pages) - 1]
|
400
|
+
total_granule = last_page.granule_position
|
401
|
+
next_page_no = last_page.page_no + 1
|
402
|
+
logger.debug("Track %d processed, next page no: %d, total granule: %d",
|
403
|
+
index + 1, next_page_no, total_granule)
|
404
|
+
finally:
|
405
|
+
handle.close()
|
406
|
+
|
407
|
+
if not no_tonie_header:
|
408
|
+
fix_tonie_header(out_file, chapters, timestamp, sha1)
|
409
|
+
|
410
|
+
if keep_temp and temp_files:
|
411
|
+
logger.info("Kept %d temporary opus files in %s", len(temp_files), os.path.dirname(temp_files[0]))
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: tonie_header.proto
|
3
|
+
|
4
|
+
import sys
|
5
|
+
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
6
|
+
from google.protobuf import descriptor as _descriptor
|
7
|
+
from google.protobuf import message as _message
|
8
|
+
from google.protobuf import reflection as _reflection
|
9
|
+
from google.protobuf import symbol_database as _symbol_database
|
10
|
+
from google.protobuf import descriptor_pb2
|
11
|
+
# @@protoc_insertion_point(imports)
|
12
|
+
|
13
|
+
_sym_db = _symbol_database.Default()
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
DESCRIPTOR = _descriptor.FileDescriptor(
|
19
|
+
name='tonie_header.proto',
|
20
|
+
package='tonie',
|
21
|
+
syntax='proto3',
|
22
|
+
serialized_pb=_b('\n\x12tonie_header.proto\x12\x05tonie\"q\n\x0bTonieHeader\x12\x10\n\x08\x64\x61taHash\x18\x01 \x01(\x0c\x12\x12\n\ndataLength\x18\x02 \x01(\r\x12\x11\n\ttimestamp\x18\x03 \x01(\r\x12\x18\n\x0c\x63hapterPages\x18\x04 \x03(\rB\x02\x10\x01\x12\x0f\n\x07padding\x18\x05 \x01(\x0c\x62\x06proto3')
|
23
|
+
)
|
24
|
+
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
_TONIEHEADER = _descriptor.Descriptor(
|
30
|
+
name='TonieHeader',
|
31
|
+
full_name='tonie.TonieHeader',
|
32
|
+
filename=None,
|
33
|
+
file=DESCRIPTOR,
|
34
|
+
containing_type=None,
|
35
|
+
fields=[
|
36
|
+
_descriptor.FieldDescriptor(
|
37
|
+
name='dataHash', full_name='tonie.TonieHeader.dataHash', index=0,
|
38
|
+
number=1, type=12, cpp_type=9, label=1,
|
39
|
+
has_default_value=False, default_value=_b(""),
|
40
|
+
message_type=None, enum_type=None, containing_type=None,
|
41
|
+
is_extension=False, extension_scope=None,
|
42
|
+
options=None),
|
43
|
+
_descriptor.FieldDescriptor(
|
44
|
+
name='dataLength', full_name='tonie.TonieHeader.dataLength', index=1,
|
45
|
+
number=2, type=13, cpp_type=3, label=1,
|
46
|
+
has_default_value=False, default_value=0,
|
47
|
+
message_type=None, enum_type=None, containing_type=None,
|
48
|
+
is_extension=False, extension_scope=None,
|
49
|
+
options=None),
|
50
|
+
_descriptor.FieldDescriptor(
|
51
|
+
name='timestamp', full_name='tonie.TonieHeader.timestamp', index=2,
|
52
|
+
number=3, type=13, cpp_type=3, label=1,
|
53
|
+
has_default_value=False, default_value=0,
|
54
|
+
message_type=None, enum_type=None, containing_type=None,
|
55
|
+
is_extension=False, extension_scope=None,
|
56
|
+
options=None),
|
57
|
+
_descriptor.FieldDescriptor(
|
58
|
+
name='chapterPages', full_name='tonie.TonieHeader.chapterPages', index=3,
|
59
|
+
number=4, type=13, cpp_type=3, label=3,
|
60
|
+
has_default_value=False, default_value=[],
|
61
|
+
message_type=None, enum_type=None, containing_type=None,
|
62
|
+
is_extension=False, extension_scope=None,
|
63
|
+
options=_descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\020\001'))),
|
64
|
+
_descriptor.FieldDescriptor(
|
65
|
+
name='padding', full_name='tonie.TonieHeader.padding', index=4,
|
66
|
+
number=5, type=12, cpp_type=9, label=1,
|
67
|
+
has_default_value=False, default_value=_b(""),
|
68
|
+
message_type=None, enum_type=None, containing_type=None,
|
69
|
+
is_extension=False, extension_scope=None,
|
70
|
+
options=None),
|
71
|
+
],
|
72
|
+
extensions=[
|
73
|
+
],
|
74
|
+
nested_types=[],
|
75
|
+
enum_types=[
|
76
|
+
],
|
77
|
+
options=None,
|
78
|
+
is_extendable=False,
|
79
|
+
syntax='proto3',
|
80
|
+
extension_ranges=[],
|
81
|
+
oneofs=[
|
82
|
+
],
|
83
|
+
serialized_start=29,
|
84
|
+
serialized_end=142,
|
85
|
+
)
|
86
|
+
|
87
|
+
DESCRIPTOR.message_types_by_name['TonieHeader'] = _TONIEHEADER
|
88
|
+
|
89
|
+
TonieHeader = _reflection.GeneratedProtocolMessageType('TonieHeader', (_message.Message,), dict(
|
90
|
+
DESCRIPTOR = _TONIEHEADER,
|
91
|
+
__module__ = 'tonie_header_pb2'
|
92
|
+
# @@protoc_insertion_point(class_scope:tonie.TonieHeader)
|
93
|
+
))
|
94
|
+
_sym_db.RegisterMessage(TonieHeader)
|
95
|
+
|
96
|
+
|
97
|
+
_TONIEHEADER.fields_by_name['chapterPages'].has_options = True
|
98
|
+
_TONIEHEADER.fields_by_name['chapterPages']._options = _descriptor._ParseOptions(descriptor_pb2.FieldOptions(), _b('\020\001'))
|
99
|
+
# @@protoc_insertion_point(module_scope)
|