pycaption 2.3.3__tar.gz → 2.3.4__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.3.3/pycaption.egg-info → pycaption-2.3.4}/PKG-INFO +1 -1
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/base.py +24 -4
- {pycaption-2.3.3 → pycaption-2.3.4/pycaption.egg-info}/PKG-INFO +1 -1
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption.egg-info/SOURCES.txt +2 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/setup.py +1 -1
- pycaption-2.3.4/tests/test_bytes_input.py +161 -0
- pycaption-2.3.4/tests/test_double_encoding.py +89 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/LICENSE +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/MANIFEST.in +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/README.rst +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/dfxp/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/dfxp/constants.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/dfxp/extras.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/dfxp/reader.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/dfxp/writer.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/exceptions.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/geometry.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/microdvd.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/sami/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/sami/constants.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/sami/parser.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/sami/reader.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/sami/writer.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/constants.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/reader.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/specialized_collections.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/state_machines.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/translator.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/scc/writer.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/srt.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/transcript.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/utils.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/webvtt/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/webvtt/constants.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/webvtt/reader.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption/webvtt/writer.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption.egg-info/dependency_links.txt +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption.egg-info/requires.txt +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/pycaption.egg-info/top_level.txt +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/setup.cfg +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/conftest.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/__init__.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/dfxp.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/microdvd.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/sami.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/scc.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/srt.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/translated_scc.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/fixtures/webvtt.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/mixins.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_base.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_dfxp.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_dfxp_conversion.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_dfxp_extras.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_functions.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_geometry.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_microdvd.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_microdvd_conversion.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_sami.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_sami_conversion.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_scc.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_scc_conversion.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_scc_translator.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_scc_writer.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_srt.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_srt_conversion.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_webvtt.py +0 -0
- {pycaption-2.3.3 → pycaption-2.3.4}/tests/test_webvtt_conversion.py +0 -0
|
@@ -5,12 +5,15 @@ CaptionSet -> CaptionList -> Caption -> CaptionNode. Also provides the
|
|
|
5
5
|
CaptionConverter orchestrator and base classes for readers/writers.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import logging
|
|
8
9
|
import os
|
|
9
10
|
from datetime import timedelta
|
|
10
11
|
from numbers import Number
|
|
11
12
|
|
|
12
13
|
from .exceptions import CaptionReadError, CaptionReadTimingError, InvalidInputError
|
|
13
14
|
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
14
17
|
# `und` a special identifier for an undetermined language according to ISO 639-2
|
|
15
18
|
DEFAULT_LANGUAGE_CODE = os.getenv("PYCAPTION_DEFAULT_LANG", "und")
|
|
16
19
|
|
|
@@ -79,9 +82,7 @@ class BaseReader:
|
|
|
79
82
|
try:
|
|
80
83
|
content = content.decode("utf-8-sig")
|
|
81
84
|
except UnicodeDecodeError as e:
|
|
82
|
-
raise InvalidInputError(
|
|
83
|
-
f"Content is not valid UTF-8: {e}"
|
|
84
|
-
) from e
|
|
85
|
+
raise InvalidInputError(f"Content is not valid UTF-8: {e}") from e
|
|
85
86
|
elif isinstance(content, str):
|
|
86
87
|
if content.startswith(""):
|
|
87
88
|
content = content[1:]
|
|
@@ -89,8 +90,23 @@ class BaseReader:
|
|
|
89
90
|
raise InvalidInputError(
|
|
90
91
|
"The content must be a unicode string or UTF-8 bytes."
|
|
91
92
|
)
|
|
93
|
+
content = BaseReader._repair_double_encoding(content)
|
|
92
94
|
return content
|
|
93
95
|
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _repair_double_encoding(text):
|
|
98
|
+
"""Fix double-encoded UTF-8 (bytes misread as CP-1252)."""
|
|
99
|
+
try:
|
|
100
|
+
repaired = text.encode("cp1252").decode("utf-8")
|
|
101
|
+
except (UnicodeEncodeError, UnicodeDecodeError):
|
|
102
|
+
return text
|
|
103
|
+
if repaired != text:
|
|
104
|
+
logger.warning(
|
|
105
|
+
"Detected and repaired double-encoded UTF-8 in caption content"
|
|
106
|
+
)
|
|
107
|
+
return repaired
|
|
108
|
+
return text
|
|
109
|
+
|
|
94
110
|
def detect(self, content):
|
|
95
111
|
"""Return True if content appears to be in this reader's format.
|
|
96
112
|
|
|
@@ -396,7 +412,11 @@ class CaptionSet:
|
|
|
396
412
|
"""
|
|
397
413
|
|
|
398
414
|
def __init__(
|
|
399
|
-
self,
|
|
415
|
+
self,
|
|
416
|
+
captions,
|
|
417
|
+
styles=None,
|
|
418
|
+
layout_info=None,
|
|
419
|
+
regions=None,
|
|
400
420
|
visual_alignment_default=None,
|
|
401
421
|
):
|
|
402
422
|
"""
|
|
@@ -41,9 +41,11 @@ tests/__init__.py
|
|
|
41
41
|
tests/conftest.py
|
|
42
42
|
tests/mixins.py
|
|
43
43
|
tests/test_base.py
|
|
44
|
+
tests/test_bytes_input.py
|
|
44
45
|
tests/test_dfxp.py
|
|
45
46
|
tests/test_dfxp_conversion.py
|
|
46
47
|
tests/test_dfxp_extras.py
|
|
48
|
+
tests/test_double_encoding.py
|
|
47
49
|
tests/test_functions.py
|
|
48
50
|
tests/test_geometry.py
|
|
49
51
|
tests/test_microdvd.py
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Tests for bytes input support across all readers.
|
|
2
|
+
|
|
3
|
+
All readers should accept bytes (raw file content) and decode as UTF-8
|
|
4
|
+
internally, preventing the double-encoding gibberish that occurs when
|
|
5
|
+
callers decode with the wrong system encoding (e.g., cp1252).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pycaption import (
|
|
9
|
+
DFXPReader,
|
|
10
|
+
MicroDVDReader,
|
|
11
|
+
SAMIReader,
|
|
12
|
+
SCCReader,
|
|
13
|
+
SRTReader,
|
|
14
|
+
WebVTTReader,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestSRTReaderBytes:
|
|
19
|
+
def setup_class(self):
|
|
20
|
+
self.reader = SRTReader()
|
|
21
|
+
|
|
22
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_srt):
|
|
23
|
+
from_str = self.reader.read(sample_srt)
|
|
24
|
+
from_bytes = self.reader.read(sample_srt.encode("utf-8"))
|
|
25
|
+
str_captions = from_str.get_captions("en-US")
|
|
26
|
+
bytes_captions = from_bytes.get_captions("en-US")
|
|
27
|
+
assert len(str_captions) == len(bytes_captions)
|
|
28
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
29
|
+
assert s.get_text() == b.get_text()
|
|
30
|
+
assert s.start == b.start
|
|
31
|
+
assert s.end == b.end
|
|
32
|
+
|
|
33
|
+
def test_read_bytes_preserves_music_notes(self, sample_srt):
|
|
34
|
+
captions = self.reader.read(sample_srt.encode("utf-8"))
|
|
35
|
+
texts = [c.get_text() for c in captions.get_captions("en-US")]
|
|
36
|
+
assert any("♪" in t for t in texts)
|
|
37
|
+
|
|
38
|
+
def test_read_bytes_with_bom(self, sample_srt):
|
|
39
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_srt.encode("utf-8")
|
|
40
|
+
captions = self.reader.read(content_with_bom)
|
|
41
|
+
assert len(captions.get_captions("en-US")) == 7
|
|
42
|
+
|
|
43
|
+
def test_detect_bytes(self, sample_srt):
|
|
44
|
+
assert self.reader.detect(sample_srt.encode("utf-8")) is True
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TestWebVTTReaderBytes:
|
|
48
|
+
def setup_class(self):
|
|
49
|
+
self.reader = WebVTTReader()
|
|
50
|
+
|
|
51
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_webvtt):
|
|
52
|
+
from_str = self.reader.read(sample_webvtt)
|
|
53
|
+
from_bytes = self.reader.read(sample_webvtt.encode("utf-8"))
|
|
54
|
+
str_captions = from_str.get_captions("en-US")
|
|
55
|
+
bytes_captions = from_bytes.get_captions("en-US")
|
|
56
|
+
assert len(str_captions) == len(bytes_captions)
|
|
57
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
58
|
+
assert s.get_text() == b.get_text()
|
|
59
|
+
|
|
60
|
+
def test_read_bytes_with_bom(self, sample_webvtt):
|
|
61
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_webvtt.encode("utf-8")
|
|
62
|
+
captions = self.reader.read(content_with_bom)
|
|
63
|
+
assert len(captions.get_captions("en-US")) > 0
|
|
64
|
+
|
|
65
|
+
def test_detect_bytes(self, sample_webvtt):
|
|
66
|
+
assert self.reader.detect(sample_webvtt.encode("utf-8")) is True
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class TestDFXPReaderBytes:
|
|
70
|
+
def setup_class(self):
|
|
71
|
+
self.reader = DFXPReader()
|
|
72
|
+
|
|
73
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_dfxp):
|
|
74
|
+
from_str = self.reader.read(sample_dfxp)
|
|
75
|
+
from_bytes = self.reader.read(sample_dfxp.encode("utf-8"))
|
|
76
|
+
for lang in from_str.get_languages():
|
|
77
|
+
str_captions = from_str.get_captions(lang)
|
|
78
|
+
bytes_captions = from_bytes.get_captions(lang)
|
|
79
|
+
assert len(str_captions) == len(bytes_captions)
|
|
80
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
81
|
+
assert s.get_text() == b.get_text()
|
|
82
|
+
|
|
83
|
+
def test_read_bytes_with_bom(self, sample_dfxp):
|
|
84
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_dfxp.encode("utf-8")
|
|
85
|
+
captions = self.reader.read(content_with_bom)
|
|
86
|
+
assert not captions.is_empty()
|
|
87
|
+
|
|
88
|
+
def test_detect_bytes(self, sample_dfxp):
|
|
89
|
+
assert self.reader.detect(sample_dfxp.encode("utf-8")) is True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class TestSAMIReaderBytes:
|
|
93
|
+
def setup_class(self):
|
|
94
|
+
self.reader = SAMIReader()
|
|
95
|
+
|
|
96
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_sami):
|
|
97
|
+
from_str = self.reader.read(sample_sami)
|
|
98
|
+
from_bytes = self.reader.read(sample_sami.encode("utf-8"))
|
|
99
|
+
for lang in from_str.get_languages():
|
|
100
|
+
str_captions = from_str.get_captions(lang)
|
|
101
|
+
bytes_captions = from_bytes.get_captions(lang)
|
|
102
|
+
assert len(str_captions) == len(bytes_captions)
|
|
103
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
104
|
+
assert s.get_text() == b.get_text()
|
|
105
|
+
|
|
106
|
+
def test_read_bytes_preserves_music_notes(self, sample_sami):
|
|
107
|
+
captions = self.reader.read(sample_sami.encode("utf-8"))
|
|
108
|
+
langs = list(captions.get_languages())
|
|
109
|
+
texts = [c.get_text() for c in captions.get_captions(langs[0])]
|
|
110
|
+
assert any("♪" in t for t in texts)
|
|
111
|
+
|
|
112
|
+
def test_read_bytes_with_bom(self, sample_sami):
|
|
113
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_sami.encode("utf-8")
|
|
114
|
+
captions = self.reader.read(content_with_bom)
|
|
115
|
+
assert not captions.is_empty()
|
|
116
|
+
|
|
117
|
+
def test_detect_bytes(self, sample_sami):
|
|
118
|
+
assert self.reader.detect(sample_sami.encode("utf-8")) is True
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TestSCCReaderBytes:
|
|
122
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_scc_pop_on):
|
|
123
|
+
from_str = SCCReader().read(sample_scc_pop_on)
|
|
124
|
+
from_bytes = SCCReader().read(sample_scc_pop_on.encode("utf-8"))
|
|
125
|
+
str_captions = from_str.get_captions("en-US")
|
|
126
|
+
bytes_captions = from_bytes.get_captions("en-US")
|
|
127
|
+
assert len(str_captions) == len(bytes_captions)
|
|
128
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
129
|
+
assert s.get_text() == b.get_text()
|
|
130
|
+
|
|
131
|
+
def test_read_bytes_with_bom(self, sample_scc_pop_on):
|
|
132
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_scc_pop_on.encode("utf-8")
|
|
133
|
+
captions = SCCReader().read(content_with_bom)
|
|
134
|
+
assert len(captions.get_captions("en-US")) > 0
|
|
135
|
+
|
|
136
|
+
def test_detect_bytes(self, sample_scc_pop_on):
|
|
137
|
+
assert SCCReader().detect(sample_scc_pop_on.encode("utf-8")) is True
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class TestMicroDVDReaderBytes:
|
|
141
|
+
def setup_class(self):
|
|
142
|
+
self.reader = MicroDVDReader()
|
|
143
|
+
|
|
144
|
+
def test_read_bytes_produces_same_result_as_str(self, sample_microdvd):
|
|
145
|
+
from_str = self.reader.read(sample_microdvd)
|
|
146
|
+
from_bytes = self.reader.read(sample_microdvd.encode("utf-8"))
|
|
147
|
+
str_captions = from_str.get_captions("und")
|
|
148
|
+
bytes_captions = from_bytes.get_captions("und")
|
|
149
|
+
assert len(str_captions) == len(bytes_captions)
|
|
150
|
+
for s, b in zip(str_captions, bytes_captions):
|
|
151
|
+
assert s.get_text() == b.get_text()
|
|
152
|
+
|
|
153
|
+
def test_read_bytes_with_bom(self, sample_microdvd):
|
|
154
|
+
content_with_bom = b"\xef\xbb\xbf" + sample_microdvd.encode("utf-8")
|
|
155
|
+
captions = self.reader.read(content_with_bom)
|
|
156
|
+
assert not captions.is_empty()
|
|
157
|
+
|
|
158
|
+
def test_detect_bytes(self, sample_microdvd):
|
|
159
|
+
assert self.reader.detect(sample_microdvd.encode("utf-8")) is True
|
|
160
|
+
|
|
161
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from pycaption import SAMIReader, SRTReader
|
|
6
|
+
from pycaption.base import BaseReader
|
|
7
|
+
from pycaption.dfxp import DFXPReader
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _double_encode(text):
|
|
11
|
+
"""Simulate double-encoding: UTF-8 bytes misread as CP-1252, re-encoded."""
|
|
12
|
+
return text.encode("utf-8").decode("cp1252")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
ORIGINAL_CHARS = ["♪", "—", "’", "é"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TestRepairDoubleEncoding:
|
|
19
|
+
@pytest.mark.parametrize("original", ORIGINAL_CHARS)
|
|
20
|
+
def test_fixes_double_encoded(self, original):
|
|
21
|
+
garbled = _double_encode(original)
|
|
22
|
+
assert BaseReader._repair_double_encoding(garbled) == original
|
|
23
|
+
|
|
24
|
+
def test_leaves_clean_utf8_alone(self):
|
|
25
|
+
clean = "♪ This is — perfectly fine é text"
|
|
26
|
+
assert BaseReader._repair_double_encoding(clean) == clean
|
|
27
|
+
|
|
28
|
+
def test_logs_warning_on_repair(self, caplog):
|
|
29
|
+
garbled = _double_encode("♪")
|
|
30
|
+
with caplog.at_level(logging.WARNING, logger="pycaption.base"):
|
|
31
|
+
BaseReader._repair_double_encoding(garbled)
|
|
32
|
+
assert "double-encoded" in caplog.text.lower()
|
|
33
|
+
|
|
34
|
+
def test_no_warning_for_clean_input(self, caplog):
|
|
35
|
+
with caplog.at_level(logging.WARNING, logger="pycaption.base"):
|
|
36
|
+
BaseReader._repair_double_encoding("♪ Music ♪")
|
|
37
|
+
assert caplog.text == ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class TestDoubleEncodingEndToEnd:
|
|
41
|
+
def test_srt_reader(self):
|
|
42
|
+
garbled_note = _double_encode("♪")
|
|
43
|
+
content = (
|
|
44
|
+
"1\n"
|
|
45
|
+
"00:00:01,000 --> 00:00:02,000\n"
|
|
46
|
+
f"{garbled_note} Music {garbled_note}\n"
|
|
47
|
+
)
|
|
48
|
+
captions = SRTReader().read(content)
|
|
49
|
+
nodes = captions.get_captions("en-US")[0].nodes
|
|
50
|
+
text = "".join(n.content for n in nodes)
|
|
51
|
+
assert "♪" in text
|
|
52
|
+
assert garbled_note not in text
|
|
53
|
+
|
|
54
|
+
def test_dfxp_reader(self):
|
|
55
|
+
garbled = _double_encode("élève")
|
|
56
|
+
content = (
|
|
57
|
+
'<?xml version="1.0" encoding="UTF-8"?>\n'
|
|
58
|
+
'<tt xml:lang="en" xmlns="http://www.w3.org/ns/ttml">\n'
|
|
59
|
+
" <body><div>\n"
|
|
60
|
+
f' <p begin="00:00:01.000" end="00:00:02.000">'
|
|
61
|
+
f"{garbled}</p>\n"
|
|
62
|
+
" </div></body>\n"
|
|
63
|
+
"</tt>\n"
|
|
64
|
+
)
|
|
65
|
+
captions = DFXPReader().read(content)
|
|
66
|
+
nodes = captions.get_captions("en")[0].nodes
|
|
67
|
+
text = "".join(n.content for n in nodes)
|
|
68
|
+
assert "élève" in text
|
|
69
|
+
assert garbled not in text
|
|
70
|
+
|
|
71
|
+
def test_sami_reader(self):
|
|
72
|
+
garbled_dash = _double_encode("—")
|
|
73
|
+
content = (
|
|
74
|
+
"<SAMI>\n"
|
|
75
|
+
"<Body>\n"
|
|
76
|
+
" <Sync Start=1000>\n"
|
|
77
|
+
f" <P Class=enCC>{garbled_dash} Hello</P>\n"
|
|
78
|
+
" </Sync>\n"
|
|
79
|
+
" <Sync Start=2000>\n"
|
|
80
|
+
" <P Class=enCC> </P>\n"
|
|
81
|
+
" </Sync>\n"
|
|
82
|
+
"</Body>\n"
|
|
83
|
+
"</SAMI>\n"
|
|
84
|
+
)
|
|
85
|
+
captions = SAMIReader().read(content)
|
|
86
|
+
lang = list(captions.get_languages())[0]
|
|
87
|
+
nodes = captions.get_captions(lang)[0].nodes
|
|
88
|
+
text = "".join(n.content for n in nodes)
|
|
89
|
+
assert "—" in text
|
|
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
|
|
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
|