pycaption 2.2.6__tar.gz → 2.2.8__tar.gz
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.
- {pycaption-2.2.6/pycaption.egg-info → pycaption-2.2.8}/PKG-INFO +1 -1
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/scc/__init__.py +47 -24
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/scc/constants.py +12 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/scc/specialized_collections.py +59 -28
- {pycaption-2.2.6 → pycaption-2.2.8/pycaption.egg-info}/PKG-INFO +1 -1
- {pycaption-2.2.6 → pycaption-2.2.8}/setup.py +1 -1
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/dfxp.py +2 -2
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/scc.py +4 -2
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_scc.py +51 -44
- {pycaption-2.2.6 → pycaption-2.2.8}/LICENSE +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/MANIFEST.in +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/README.rst +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/__init__.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/base.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/dfxp/__init__.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/dfxp/base.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/dfxp/extras.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/english.pickle +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/exceptions.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/geometry.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/microdvd.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/sami.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/scc/state_machines.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/scc/translator.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/srt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/transcript.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/utils.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption/webvtt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption.egg-info/SOURCES.txt +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption.egg-info/dependency_links.txt +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption.egg-info/requires.txt +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/pycaption.egg-info/top_level.txt +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/setup.cfg +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/__init__.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/conftest.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/__init__.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/microdvd.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/sami.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/srt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/translated_scc.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/fixtures/webvtt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/mixins.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_base.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_dfxp.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_dfxp_conversion.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_dfxp_extras.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_functions.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_geometry.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_microdvd.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_microdvd_conversion.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_sami.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_sami_conversion.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_scc_conversion.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_scc_translator.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_srt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_srt_conversion.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_webvtt.py +0 -0
- {pycaption-2.2.6 → pycaption-2.2.8}/tests/test_webvtt_conversion.py +0 -0
|
@@ -308,15 +308,21 @@ class SCCReader(BaseReader):
|
|
|
308
308
|
|
|
309
309
|
self.time_translator.start_at(parts[0][0])
|
|
310
310
|
|
|
311
|
-
|
|
312
|
-
|
|
311
|
+
word_list = parts[0][2].split(' ')
|
|
312
|
+
pacs_are_doubled = len(word_list) > 1 and word_list[0] == word_list[1]
|
|
313
|
+
for idx, word in enumerate(word_list):
|
|
313
314
|
# ignore empty results or invalid commands
|
|
314
315
|
word = word.strip()
|
|
316
|
+
previous_is_pac = idx > 0 and _is_pac_command(word_list[idx-1])
|
|
315
317
|
if len(word) == 4:
|
|
316
|
-
self._translate_word(
|
|
318
|
+
self._translate_word(
|
|
319
|
+
word=word,
|
|
320
|
+
previous_is_pac=previous_is_pac,
|
|
321
|
+
pacs_are_doubled=pacs_are_doubled
|
|
322
|
+
)
|
|
317
323
|
|
|
318
|
-
def _translate_word(self, word):
|
|
319
|
-
if self._handle_double_command(word):
|
|
324
|
+
def _translate_word(self, word, previous_is_pac, pacs_are_doubled):
|
|
325
|
+
if self._handle_double_command(word, pacs_are_doubled):
|
|
320
326
|
# count frames for timing
|
|
321
327
|
self.time_translator.increment_frames()
|
|
322
328
|
return
|
|
@@ -324,7 +330,7 @@ class SCCReader(BaseReader):
|
|
|
324
330
|
# TODO - check that all the positioning commands are here, or use
|
|
325
331
|
# some other strategy to determine if the word is a command.
|
|
326
332
|
if word in COMMANDS or _is_pac_command(word):
|
|
327
|
-
self._translate_command(word)
|
|
333
|
+
self._translate_command(word=word, previous_is_pac=previous_is_pac)
|
|
328
334
|
|
|
329
335
|
# second, check if word is a special character
|
|
330
336
|
elif word in SPECIAL_CHARS:
|
|
@@ -340,42 +346,56 @@ class SCCReader(BaseReader):
|
|
|
340
346
|
# count frames for timing only after processing a command
|
|
341
347
|
self.time_translator.increment_frames()
|
|
342
348
|
|
|
343
|
-
def _handle_double_command(self, word):
|
|
349
|
+
def _handle_double_command(self, word, pacs_are_doubled):
|
|
344
350
|
# If the caption is to be broadcast, each of the commands are doubled
|
|
345
351
|
# up for redundancy in case the signal is garbled in transmission.
|
|
346
352
|
# The decoder is programmed to ignore a second command when it is the
|
|
347
353
|
# same as the first.
|
|
348
|
-
#
|
|
354
|
+
# If we have doubled commands we're skipping also
|
|
355
|
+
# doubled special characters and doubled extended characters
|
|
349
356
|
# with only one member of each pair being displayed.
|
|
350
|
-
|
|
351
|
-
if
|
|
352
|
-
|
|
353
|
-
|
|
357
|
+
actionable_commands = {
|
|
358
|
+
key: COMMANDS[key] for key in COMMANDS.keys() if key != "94a1"
|
|
359
|
+
}
|
|
360
|
+
doubled_types = word in actionable_commands or _is_pac_command(word)
|
|
361
|
+
if pacs_are_doubled:
|
|
362
|
+
doubled_types = doubled_types or word in SPECIAL_CHARS or word in EXTENDED_CHARS
|
|
363
|
+
|
|
364
|
+
if doubled_types and word == self.last_command:
|
|
365
|
+
return True
|
|
354
366
|
# Fix for the <position> <tab offset> <position> <tab offset>
|
|
355
367
|
# repetition
|
|
356
|
-
|
|
357
|
-
|
|
368
|
+
elif _is_pac_command(word) and word in self.last_command:
|
|
369
|
+
self.last_command = ''
|
|
370
|
+
return True
|
|
371
|
+
elif word in PAC_TAB_OFFSET_COMMANDS:
|
|
372
|
+
if _is_pac_command(self.last_command):
|
|
373
|
+
self.last_command += f" {word}"
|
|
374
|
+
return False
|
|
375
|
+
else:
|
|
358
376
|
return True
|
|
359
|
-
elif word in PAC_TAB_OFFSET_COMMANDS:
|
|
360
|
-
if _is_pac_command(self.last_command):
|
|
361
|
-
self.last_command += f" {word}"
|
|
362
|
-
return False
|
|
363
|
-
else:
|
|
364
|
-
return True
|
|
365
377
|
|
|
366
378
|
self.last_command = word
|
|
367
379
|
return False
|
|
368
380
|
|
|
369
381
|
def _translate_special_char(self, word):
|
|
382
|
+
self.buffer.handle_backspace(word)
|
|
383
|
+
# add to buffer
|
|
370
384
|
self.buffer.add_chars(SPECIAL_CHARS[word])
|
|
371
385
|
|
|
372
386
|
def _translate_extended_char(self, word):
|
|
373
|
-
|
|
374
|
-
|
|
387
|
+
"""
|
|
388
|
+
Each of the 64 Extended Characters incorporates an automatic BS.
|
|
389
|
+
When an Extended Character is received, the cursor moves to the
|
|
390
|
+
left one column position (unless the Extended Character is the first
|
|
391
|
+
character on a row), erasing any character which may be in that location,
|
|
392
|
+
then displays the Extended Character.
|
|
393
|
+
"""
|
|
394
|
+
self.buffer.handle_backspace(word)
|
|
375
395
|
# add to buffer
|
|
376
396
|
self.buffer.add_chars(EXTENDED_CHARS[word])
|
|
377
397
|
|
|
378
|
-
def _translate_command(self, word):
|
|
398
|
+
def _translate_command(self, word, previous_is_pac):
|
|
379
399
|
# if command is pop_up
|
|
380
400
|
if word == '9420':
|
|
381
401
|
self.buffer_dict.set_active('pop')
|
|
@@ -444,7 +464,10 @@ class SCCReader(BaseReader):
|
|
|
444
464
|
|
|
445
465
|
# If command is not one of the aforementioned, add it to buffer
|
|
446
466
|
else:
|
|
447
|
-
self.buffer.interpret_command(
|
|
467
|
+
self.buffer.interpret_command(
|
|
468
|
+
command=word,
|
|
469
|
+
previous_is_pac=previous_is_pac
|
|
470
|
+
)
|
|
448
471
|
|
|
449
472
|
def _translate_characters(self, word):
|
|
450
473
|
# split word into the 2 bytes
|
|
@@ -1046,3 +1046,15 @@ INCONVERTIBLE_TO_ASCII_EXTENDED_CHARS_ASSOCIATION = {
|
|
|
1046
1046
|
'└': ["+"],
|
|
1047
1047
|
'┘': ["+"]
|
|
1048
1048
|
}
|
|
1049
|
+
|
|
1050
|
+
MID_ROW_CODES = [
|
|
1051
|
+
"9120", "91a1", "91a2", "9123", "91a4", "9125", "9126",
|
|
1052
|
+
"91a7", "91a8", "9129", "912a", "91ab", "912c", "91ad",
|
|
1053
|
+
"97ae", "972f", "91ae", "912f", "94a8"
|
|
1054
|
+
]
|
|
1055
|
+
|
|
1056
|
+
BACKGROUND_COLOR_CODES = [
|
|
1057
|
+
"1020", "10a1", "10a2", "1023", "10a4", "1025", "1026",
|
|
1058
|
+
"10a7", "10a8", "1029", "102a", "10ab", "102c", "10ad",
|
|
1059
|
+
"10ae", "102f", "97ad"
|
|
1060
|
+
]
|
|
@@ -8,7 +8,8 @@ from ..geometry import (
|
|
|
8
8
|
)
|
|
9
9
|
from .constants import (
|
|
10
10
|
PAC_BYTES_TO_POSITIONING_MAP, COMMANDS, PAC_TAB_OFFSET_COMMANDS,
|
|
11
|
-
MICROSECONDS_PER_CODEWORD,
|
|
11
|
+
MICROSECONDS_PER_CODEWORD, BACKGROUND_COLOR_CODES,
|
|
12
|
+
MID_ROW_CODES, EXTENDED_CHARS, SPECIAL_CHARS
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
PopOnCue = collections.namedtuple("PopOnCue", "buffer, start, end")
|
|
@@ -254,7 +255,7 @@ class CaptionCreator:
|
|
|
254
255
|
layout_info = _get_layout_from_tuple(instruction.position)
|
|
255
256
|
caption.nodes.append(
|
|
256
257
|
CaptionNode.create_text(
|
|
257
|
-
instruction.
|
|
258
|
+
instruction.text, layout_info=layout_info),
|
|
258
259
|
)
|
|
259
260
|
caption.layout_info = layout_info
|
|
260
261
|
|
|
@@ -287,6 +288,8 @@ class InstructionNodeCreator:
|
|
|
287
288
|
else:
|
|
288
289
|
self._collection = collection
|
|
289
290
|
|
|
291
|
+
self.last_style = None
|
|
292
|
+
|
|
290
293
|
self._position_tracer = position_tracker
|
|
291
294
|
|
|
292
295
|
def is_empty(self):
|
|
@@ -334,24 +337,40 @@ class InstructionNodeCreator:
|
|
|
334
337
|
|
|
335
338
|
node.add_chars(*chars)
|
|
336
339
|
|
|
337
|
-
def interpret_command(self, command):
|
|
340
|
+
def interpret_command(self, command, previous_is_pac=None):
|
|
338
341
|
"""Given a command determines whether to turn italics on or off,
|
|
339
342
|
or to set the positioning
|
|
340
343
|
|
|
341
344
|
This is mostly used to convert from the legacy-style commands
|
|
342
345
|
|
|
343
346
|
:type command: str
|
|
347
|
+
:type mode: pop or roll or paint
|
|
344
348
|
"""
|
|
345
349
|
self._update_positioning(command)
|
|
346
350
|
|
|
347
351
|
text = COMMANDS.get(command, '')
|
|
348
352
|
|
|
353
|
+
if command == "94a1":
|
|
354
|
+
self.handle_backspace("94a1")
|
|
355
|
+
|
|
356
|
+
if command in BACKGROUND_COLOR_CODES:
|
|
357
|
+
# Since these codes are optional, they must be preceded
|
|
358
|
+
# with the space character (20h),
|
|
359
|
+
# which will be deleted when the code is applied.
|
|
360
|
+
# ex: 2080 97ad 94a1
|
|
361
|
+
if (
|
|
362
|
+
self._collection[-1].is_text_node() and
|
|
363
|
+
self._collection[-1].text[-1].isspace()
|
|
364
|
+
):
|
|
365
|
+
self._collection[-1].text = self._collection[-1].text[:-1]
|
|
366
|
+
|
|
349
367
|
if 'italic' in text:
|
|
350
368
|
if 'end' not in text:
|
|
351
369
|
self._collection.append(
|
|
352
370
|
_InstructionNode.create_italics_style(
|
|
353
371
|
self._position_tracer.get_current_position())
|
|
354
372
|
)
|
|
373
|
+
self.last_style = "italics on"
|
|
355
374
|
else:
|
|
356
375
|
self._collection.append(
|
|
357
376
|
_InstructionNode.create_italics_style(
|
|
@@ -359,6 +378,19 @@ class InstructionNodeCreator:
|
|
|
359
378
|
turn_on=False
|
|
360
379
|
)
|
|
361
380
|
)
|
|
381
|
+
self.last_style = "italics off"
|
|
382
|
+
|
|
383
|
+
# mid row code that is not first code on the line
|
|
384
|
+
# (previous node is not a break node)
|
|
385
|
+
# fixes OCTO-11022
|
|
386
|
+
if command in MID_ROW_CODES and not previous_is_pac:
|
|
387
|
+
if self.last_style == "italics off":
|
|
388
|
+
self.add_chars(' ')
|
|
389
|
+
else:
|
|
390
|
+
for node in self._collection[::-1]:
|
|
391
|
+
if node.is_text_node() and node.text:
|
|
392
|
+
node.text += ' '
|
|
393
|
+
break
|
|
362
394
|
|
|
363
395
|
def _update_positioning(self, command):
|
|
364
396
|
"""Sets the positioning information to use for the next nodes
|
|
@@ -412,33 +444,32 @@ class InstructionNodeCreator:
|
|
|
412
444
|
|
|
413
445
|
return instance
|
|
414
446
|
|
|
415
|
-
def
|
|
447
|
+
def handle_backspace(self, word):
|
|
416
448
|
"""
|
|
417
|
-
|
|
418
|
-
their ASCII substitute, in case the decoder is not able to display
|
|
419
|
-
the special character.
|
|
420
|
-
|
|
421
|
-
This is used to remove the substitute character in order to avoid
|
|
422
|
-
displaying both.
|
|
423
|
-
|
|
424
|
-
:type accented_character: str
|
|
449
|
+
Move cursor back one position and delete that character
|
|
425
450
|
"""
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
451
|
+
node = self.get_previous_text_node()
|
|
452
|
+
# in case of no previous text nodes or
|
|
453
|
+
# if the backspace is required while no character
|
|
454
|
+
# do nothing
|
|
455
|
+
if node is None:
|
|
456
|
+
return
|
|
457
|
+
last_char = node.text[-1]
|
|
458
|
+
delete_previous_condition = (
|
|
459
|
+
(word in SPECIAL_CHARS and last_char not in SPECIAL_CHARS.values()) or
|
|
460
|
+
(word in EXTENDED_CHARS and last_char not in EXTENDED_CHARS.values()) or
|
|
461
|
+
word == "94a1"
|
|
462
|
+
)
|
|
463
|
+
# in case of special / extended char, perform backspace
|
|
464
|
+
# only if the previous character in not also special / extended
|
|
465
|
+
if delete_previous_condition:
|
|
466
|
+
node.text = node.text[:-1]
|
|
467
|
+
|
|
468
|
+
def get_previous_text_node(self):
|
|
469
|
+
for node in self._collection[::-1]:
|
|
470
|
+
if node.is_text_node() and node.text:
|
|
471
|
+
return node
|
|
472
|
+
return None
|
|
442
473
|
|
|
443
474
|
|
|
444
475
|
def _get_layout_from_tuple(position_tuple):
|
|
@@ -920,10 +920,10 @@ def sample_dfxp_from_scc_output():
|
|
|
920
920
|
<region tts:displayAlign="before" tts:origin="40% 53%" tts:textAlign="left" xml:id="r5"/>
|
|
921
921
|
<region tts:displayAlign="before" tts:origin="70% 17%" tts:textAlign="left" xml:id="r6"/>
|
|
922
922
|
<region tts:displayAlign="before" tts:origin="20% 35%" tts:textAlign="left" xml:id="r7"/>
|
|
923
|
-
<region tts:displayAlign="before" tts:origin="
|
|
923
|
+
<region tts:displayAlign="before" tts:origin="25% 83%" tts:textAlign="left" xml:id="r8"/>
|
|
924
924
|
<region tts:displayAlign="before" tts:origin="70% 11%" tts:textAlign="left" xml:id="r9"/>
|
|
925
925
|
<region tts:displayAlign="before" tts:origin="40% 41%" tts:textAlign="left" xml:id="r10"/>
|
|
926
|
-
<region tts:displayAlign="before" tts:origin="
|
|
926
|
+
<region tts:displayAlign="before" tts:origin="25% 71%" tts:textAlign="left" xml:id="r11"/>
|
|
927
927
|
</layout>
|
|
928
928
|
</head>
|
|
929
929
|
<body>
|
|
@@ -367,9 +367,11 @@ def sample_scc_duplicate_special_characters():
|
|
|
367
367
|
return """\
|
|
368
368
|
Scenarist_SCC V1.0
|
|
369
369
|
|
|
370
|
-
00:23:28;01 9420 91b0 91b0 9131 9131 9132 9132 91b3 91b3 9134 9134 91b5 91b5 91b6 91b6 9137 9137 9138 9138 91b9 91b9 91ba 91ba 913b 913b 91bc 91bc 913d 913d 913e 913e 91bf 91bf 942f
|
|
370
|
+
00:23:28;01 9420 9420 91b0 91b0 9131 9131 9132 9132 91b3 91b3 9134 9134 91b5 91b5 91b6 91b6 9137 9137 9138 9138 91b9 91b9 91ba 91ba 913b 913b 91bc 91bc 913d 913d 913e 913e 91bf 91bf 942f
|
|
371
371
|
|
|
372
|
-
00:
|
|
372
|
+
00:33:28;01 9420 91b0 9131 9132 91b3 9134 91b5 91b6 9137 9138 91b9 91ba 913b 91bc 913d 913e 91bf 942f
|
|
373
|
+
|
|
374
|
+
00:53:28;01 9420 91b0 9131 c1c1 9132 91b3 9134 91b5 91b6 9137 9138 91b9 91ba 913b 91bc c1c1 913d 913e 91bf 942f
|
|
373
375
|
|
|
374
376
|
"""
|
|
375
377
|
|
|
@@ -77,17 +77,15 @@ class TestSCCReader(ReaderTestingMixIn):
|
|
|
77
77
|
((40.0, UnitEnum.PERCENT), (53.0, UnitEnum.PERCENT)),
|
|
78
78
|
((70.0, UnitEnum.PERCENT), (17.0, UnitEnum.PERCENT)),
|
|
79
79
|
((20.0, UnitEnum.PERCENT), (35.0, UnitEnum.PERCENT)),
|
|
80
|
-
((
|
|
80
|
+
((25.0, UnitEnum.PERCENT), (83.0, UnitEnum.PERCENT)),
|
|
81
81
|
((70.0, UnitEnum.PERCENT), (11.0, UnitEnum.PERCENT)),
|
|
82
82
|
((40.0, UnitEnum.PERCENT), (41.0, UnitEnum.PERCENT)),
|
|
83
|
-
((
|
|
83
|
+
((25.0, UnitEnum.PERCENT), (71.0, UnitEnum.PERCENT))
|
|
84
84
|
]
|
|
85
|
-
|
|
86
85
|
actual_positioning = [
|
|
87
86
|
caption_.layout_info.origin.serialized()
|
|
88
87
|
for caption_ in captions.get_captions('en-US')
|
|
89
88
|
]
|
|
90
|
-
|
|
91
89
|
assert expected_positioning == actual_positioning
|
|
92
90
|
|
|
93
91
|
def test_tab_offset(self, sample_scc_tab_offset):
|
|
@@ -206,11 +204,11 @@ class TestSCCReader(ReaderTestingMixIn):
|
|
|
206
204
|
|
|
207
205
|
def test_skip_duplicate_tab_offset(self, sample_scc_duplicate_tab_offset):
|
|
208
206
|
expected_lines = [
|
|
209
|
-
'[Radio reporter]',
|
|
210
|
-
'The I-10 Santa Monica Freeway',
|
|
207
|
+
'[Radio reporter] ',
|
|
208
|
+
'The I-10 Santa Monica Freeway ',
|
|
211
209
|
'westbound is jammed,',
|
|
212
|
-
'due to a three-car accident',
|
|
213
|
-
'blocking lanes 1 and 2'
|
|
210
|
+
'due to a three-car accident ',
|
|
211
|
+
'blocking lanes 1 and 2'
|
|
214
212
|
]
|
|
215
213
|
|
|
216
214
|
caption_set = SCCReader().read(sample_scc_duplicate_tab_offset)
|
|
@@ -225,7 +223,11 @@ class TestSCCReader(ReaderTestingMixIn):
|
|
|
225
223
|
|
|
226
224
|
def test_skip_duplicate_special_characters(
|
|
227
225
|
self, sample_scc_duplicate_special_characters):
|
|
228
|
-
expected_lines = [
|
|
226
|
+
expected_lines = [
|
|
227
|
+
'®°½¿™¢£♪à èâêîôû', # double commands so we skip one
|
|
228
|
+
'®°½¿™¢£♪à èâêîôû', # no double command, nothing skipped equal with above
|
|
229
|
+
'®°A½¿™¢£♪à èâêAîôû' # no skips but a couple of normal chars "c1c1" = AA
|
|
230
|
+
]
|
|
229
231
|
|
|
230
232
|
caption_set = SCCReader().read(sample_scc_duplicate_special_characters)
|
|
231
233
|
actual_lines = [
|
|
@@ -234,7 +236,6 @@ class TestSCCReader(ReaderTestingMixIn):
|
|
|
234
236
|
for node in cap_.nodes
|
|
235
237
|
if node.type_ == CaptionNode.TEXT
|
|
236
238
|
]
|
|
237
|
-
|
|
238
239
|
assert expected_lines == actual_lines
|
|
239
240
|
|
|
240
241
|
def test_flashing_cue(self, sample_scc_flashing_cue):
|
|
@@ -273,21 +274,21 @@ class TestCoverageOnly:
|
|
|
273
274
|
actual_texts = [cap_.nodes[0].content for cap_ in captions]
|
|
274
275
|
expected_texts = [
|
|
275
276
|
'>>> HI.',
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
277
|
+
"I'M KEVIN CUNNING AND AT",
|
|
278
|
+
"INVESTOR'S BANK WE BELIEVE IN",
|
|
279
|
+
'HELPING THE LOCAL NEIGHBORHOODS',
|
|
280
|
+
'AND IMPROVING THE LIVES OF ALL',
|
|
281
|
+
'WE SERVE.',
|
|
282
|
+
'®°½',
|
|
283
|
+
'Aû',
|
|
284
|
+
'ÁÉÓ¡',
|
|
285
|
+
"WHERE YOU'RE STANDING NOW,",
|
|
286
|
+
"LOOKING OUT THERE, THAT'S AL",
|
|
287
|
+
'THE CROWD.',
|
|
288
|
+
'>> IT WAS GOOD TO BE IN TH',
|
|
289
|
+
"And restore Iowa's land, water",
|
|
290
|
+
'And wildlife.',
|
|
291
|
+
'>> Bike Iowa, your source for'
|
|
291
292
|
]
|
|
292
293
|
assert expected_texts == actual_texts
|
|
293
294
|
|
|
@@ -383,6 +384,9 @@ class TestInterpretableNodeCreator:
|
|
|
383
384
|
# 4. to get new opening italic nodes after changing position, if 3
|
|
384
385
|
# happened
|
|
385
386
|
# 5. to get a final italic closing node, if one is needed
|
|
387
|
+
# 9120 and 91ae are mid row codes and will add a space
|
|
388
|
+
# 9120 at the start of the following text node
|
|
389
|
+
# 91ae to the end of the previous text node
|
|
386
390
|
node_creator.interpret_command('9470') # row 15, col 0
|
|
387
391
|
node_creator.interpret_command('9120') # italics off
|
|
388
392
|
node_creator.interpret_command('9120') # italics off
|
|
@@ -401,7 +405,7 @@ class TestInterpretableNodeCreator:
|
|
|
401
405
|
node_creator.add_chars('b')
|
|
402
406
|
node_creator.interpret_command('91ae') # italics ON again
|
|
403
407
|
node_creator.add_chars('b')
|
|
404
|
-
node_creator.interpret_command('9120') # italics OFF
|
|
408
|
+
node_creator.interpret_command('9120') # italics OFF adds space
|
|
405
409
|
node_creator.interpret_command('9120') # italics OFF
|
|
406
410
|
|
|
407
411
|
node_creator.interpret_command('1570') # row 6 col 0
|
|
@@ -420,32 +424,35 @@ class TestInterpretableNodeCreator:
|
|
|
420
424
|
result = list(node_creator)
|
|
421
425
|
|
|
422
426
|
assert result[0].is_text_node()
|
|
423
|
-
assert result[1].
|
|
424
|
-
assert result[2].
|
|
425
|
-
assert result[2].sets_italics_on()
|
|
427
|
+
assert result[1].is_text_node()
|
|
428
|
+
assert result[2].requires_repositioning()
|
|
426
429
|
|
|
427
|
-
assert result[3].
|
|
430
|
+
assert result[3].is_italics_node()
|
|
431
|
+
assert result[3].sets_italics_on()
|
|
428
432
|
assert result[4].is_text_node()
|
|
429
|
-
assert result[5].
|
|
430
|
-
|
|
431
|
-
assert result[6].is_italics_node()
|
|
432
|
-
assert result[6].sets_italics_off()
|
|
433
|
+
assert result[5].sets_italics_off()
|
|
434
|
+
assert result[6].is_text_node()
|
|
433
435
|
|
|
434
|
-
assert result[7].
|
|
435
|
-
assert result[8].
|
|
436
|
+
assert result[7].is_text_node()
|
|
437
|
+
assert result[8].sets_italics_on()
|
|
436
438
|
|
|
437
|
-
assert result[9].
|
|
438
|
-
assert result[10].
|
|
439
|
-
assert result[10].sets_italics_on()
|
|
439
|
+
assert result[9].is_text_node()
|
|
440
|
+
assert result[10].is_text_node()
|
|
440
441
|
|
|
441
|
-
assert result[11].
|
|
442
|
-
assert result[12].
|
|
442
|
+
assert result[11].sets_italics_off()
|
|
443
|
+
assert result[12].is_text_node()
|
|
443
444
|
assert result[13].is_text_node()
|
|
444
|
-
assert result[14].
|
|
445
|
+
assert result[14].requires_repositioning()
|
|
445
446
|
assert result[15].is_text_node()
|
|
446
447
|
|
|
447
|
-
assert result[16].
|
|
448
|
-
assert result[
|
|
448
|
+
assert result[16].requires_repositioning()
|
|
449
|
+
assert result[17].sets_italics_on()
|
|
450
|
+
assert result[18].is_text_node()
|
|
451
|
+
assert result[19].is_explicit_break()
|
|
452
|
+
assert result[20].is_text_node()
|
|
453
|
+
assert result[21].is_explicit_break()
|
|
454
|
+
assert result[22].is_text_node()
|
|
455
|
+
assert result[23].sets_italics_off()
|
|
449
456
|
|
|
450
457
|
|
|
451
458
|
class CaptionDummy:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|