mkv-episode-matcher 0.1.5__py3-none-any.whl → 0.1.9__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.
Potentially problematic release.
This version of mkv-episode-matcher might be problematic. Click here for more details.
- mkv_episode_matcher/__init__.py +1 -1
- mkv_episode_matcher/__main__.py +2 -2
- mkv_episode_matcher/libraries/pgs2srt/.gitignore +2 -2
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/SubZero.py +295 -295
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/dictionaries/data.py +249 -249
- mkv_episode_matcher/libraries/pgs2srt/Libraries/SubZero/post_processing.py +215 -215
- mkv_episode_matcher/libraries/pgs2srt/README.md +26 -26
- mkv_episode_matcher/libraries/pgs2srt/imagemaker.py +87 -87
- mkv_episode_matcher/libraries/pgs2srt/pgs2srt.py +121 -121
- mkv_episode_matcher/libraries/pgs2srt/pgsreader.py +221 -221
- mkv_episode_matcher/libraries/pgs2srt/requirements.txt +4 -4
- mkv_episode_matcher/mkv_to_srt.py +174 -174
- mkv_episode_matcher/notebooks/get_subtitles_test.ipynb +252 -0
- mkv_episode_matcher/requirements.txt +6 -7
- mkv_episode_matcher/utils.py +5 -2
- {mkv_episode_matcher-0.1.5.dist-info → mkv_episode_matcher-0.1.9.dist-info}/METADATA +53 -37
- mkv_episode_matcher-0.1.9.dist-info/RECORD +25 -0
- {mkv_episode_matcher-0.1.5.dist-info → mkv_episode_matcher-0.1.9.dist-info}/WHEEL +2 -1
- mkv_episode_matcher-0.1.9.dist-info/top_level.txt +1 -0
- mkv_episode_matcher/libraries/pgs2srt/.git +0 -1
- mkv_episode_matcher-0.1.5.dist-info/RECORD +0 -24
- {mkv_episode_matcher-0.1.5.dist-info → mkv_episode_matcher-0.1.9.dist-info}/entry_points.txt +0 -0
|
@@ -1,215 +1,215 @@
|
|
|
1
|
-
# MIT License
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2018 Hannes Tismer
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
# furnished to do so, subject to the following conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
# copies or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
# SOFTWARE.
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
# Copyright for portions of project Sub-Zero are held by Bram Walet, 2014 as part of project Subliminal.bundle.
|
|
25
|
-
# The original license is supplied below.
|
|
26
|
-
#
|
|
27
|
-
# The MIT License (MIT)
|
|
28
|
-
#
|
|
29
|
-
# Copyright (c) 2014 Bram Walet
|
|
30
|
-
#
|
|
31
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
33
|
-
# in the Software without restriction, including without limitation the rights
|
|
34
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
36
|
-
# furnished to do so, subject to the following conditions:
|
|
37
|
-
#
|
|
38
|
-
# The above copyright notice and this permission notice shall be included in all
|
|
39
|
-
# copies or substantial portions of the Software.
|
|
40
|
-
#
|
|
41
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
-
# SOFTWARE.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
import re
|
|
51
|
-
|
|
52
|
-
from tld import get_tld
|
|
53
|
-
|
|
54
|
-
from Libraries.SubZero.dictionaries.data import data
|
|
55
|
-
from Libraries.SubZero.SubZero import (
|
|
56
|
-
MultipleLineProcessor,
|
|
57
|
-
MultipleWordReProcessor,
|
|
58
|
-
NReProcessor,
|
|
59
|
-
ReProcessor,
|
|
60
|
-
SubtitleTextModification,
|
|
61
|
-
WholeLineProcessor,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class CommonFixes(SubtitleTextModification):
|
|
66
|
-
identifier = "common"
|
|
67
|
-
description = "Basic common fixes"
|
|
68
|
-
exclusive = True
|
|
69
|
-
order = 40
|
|
70
|
-
|
|
71
|
-
long_description = "Fix common and whitespace/punctuation issues in subtitles"
|
|
72
|
-
|
|
73
|
-
processors = [
|
|
74
|
-
# normalize hyphens
|
|
75
|
-
NReProcessor(re.compile(r'(?u)([‑‐﹘﹣])'), "-", name="CM_hyphens"),
|
|
76
|
-
|
|
77
|
-
# -- = em dash
|
|
78
|
-
NReProcessor(re.compile(r'(?u)(\w|\b|\s|^)(-\s?-{1,2})'), r"\1—", name="CM_multidash"),
|
|
79
|
-
|
|
80
|
-
# line = _/-/\s
|
|
81
|
-
NReProcessor(re.compile(r'(?u)(^\W*[-_.:<>~"\']+\W*$)'), "", name="CM_non_word_only"),
|
|
82
|
-
|
|
83
|
-
# remove >>
|
|
84
|
-
NReProcessor(re.compile(r'(?u)^\s?>>\s*'), "", name="CM_leading_crocodiles"),
|
|
85
|
-
|
|
86
|
-
# line = : text
|
|
87
|
-
NReProcessor(re.compile(r'(?u)(^\W*:\s*(?=\w+))'), "", name="CM_empty_colon_start"),
|
|
88
|
-
|
|
89
|
-
# fix music symbols
|
|
90
|
-
NReProcessor(re.compile(r'(?u)(^[-\s>~]*[*#¶]+\s+)|(\s*[*#¶]+\s*$)'),
|
|
91
|
-
lambda x: "♪ " if x.group(1) else " ♪",
|
|
92
|
-
name="CM_music_symbols"),
|
|
93
|
-
|
|
94
|
-
# '' = "
|
|
95
|
-
NReProcessor(re.compile(r'(?u)([\'’ʼ❜‘‛][\'’ʼ❜‘‛]+)'), '"', name="CM_double_apostrophe"),
|
|
96
|
-
|
|
97
|
-
# double quotes instead of single quotes inside words
|
|
98
|
-
NReProcessor(re.compile(r'(?u)([A-zÀ-ž])"([A-zÀ-ž])'), r"\1'\2", name="CM_double_as_single"),
|
|
99
|
-
|
|
100
|
-
# normalize quotes
|
|
101
|
-
NReProcessor(re.compile(r'(?u)(\s*["”“‟„])\s*(["”“‟„]["”“‟„\s]*)'),
|
|
102
|
-
lambda match: '"' + (" " if match.group(2).endswith(" ") else ""),
|
|
103
|
-
name="CM_normalize_quotes"),
|
|
104
|
-
|
|
105
|
-
# normalize single quotes
|
|
106
|
-
NReProcessor(re.compile(r'(?u)([\'’ʼ❜‘‛])'), "'", name="CM_normalize_squotes"),
|
|
107
|
-
|
|
108
|
-
# remove leading ...
|
|
109
|
-
NReProcessor(re.compile(r'(?u)^\.\.\.[\s]*'), "", name="CM_leading_ellipsis"),
|
|
110
|
-
|
|
111
|
-
# remove "downloaded from" tags
|
|
112
|
-
NReProcessor(re.compile(r'(?ui).+downloaded\s+from.+'), "", name="CM_crap"),
|
|
113
|
-
|
|
114
|
-
# no space after ellipsis
|
|
115
|
-
NReProcessor(re.compile(r'(?u)\.\.\.(?![\s.,!?\'"])(?!$)'), "... ", name="CM_ellipsis_no_space"),
|
|
116
|
-
|
|
117
|
-
# no space before spaced ellipsis
|
|
118
|
-
NReProcessor(re.compile(r'(?u)(?<=[^\s])(?<!\s)\. \. \.'), " . . .", name="CM_ellipsis_no_space2"),
|
|
119
|
-
|
|
120
|
-
# multiple spaces
|
|
121
|
-
NReProcessor(re.compile(r'(?u)[\s]{2,}'), " ", name="CM_multiple_spaces"),
|
|
122
|
-
|
|
123
|
-
# more than 3 dots
|
|
124
|
-
NReProcessor(re.compile(r'(?u)\.{3,}'), "...", name="CM_dots"),
|
|
125
|
-
|
|
126
|
-
# no space after starting dash
|
|
127
|
-
NReProcessor(re.compile(r'(?u)^-(?![\s-])'), "- ", name="CM_dash_space"),
|
|
128
|
-
|
|
129
|
-
# remove starting spaced dots (not matching ellipses)
|
|
130
|
-
NReProcessor(re.compile(r'(?u)^(?!\s?(\.\s\.\s\.)|(\s?\.{3}))(?=\.+\s+)[\s.]*'), "",
|
|
131
|
-
name="CM_starting_spacedots"),
|
|
132
|
-
|
|
133
|
-
# space missing before doublequote
|
|
134
|
-
ReProcessor(re.compile(r'(?u)(?<!^)(?<![\s(\["])("[^"]+")'), r' \1', name="CM_space_before_dblquote"),
|
|
135
|
-
|
|
136
|
-
# space missing after doublequote
|
|
137
|
-
ReProcessor(re.compile(r'(?u)("[^"\s][^"]+")([^\s.,!?)\]]+)'), r"\1 \2", name="CM_space_after_dblquote"),
|
|
138
|
-
|
|
139
|
-
# space before ending doublequote?
|
|
140
|
-
|
|
141
|
-
# replace uppercase I with lowercase L in words
|
|
142
|
-
NReProcessor(re.compile(r'(?u)([a-zà-ž]+)(I+)'),
|
|
143
|
-
lambda match: r'%s%s' % (match.group(1), "l" * len(match.group(2))),
|
|
144
|
-
name="CM_uppercase_i_in_word"),
|
|
145
|
-
|
|
146
|
-
# fix spaces in numbers (allows for punctuation: ,.:' (comma/dot only fixed if after space, those may be
|
|
147
|
-
# countdowns otherwise); don't break up ellipses
|
|
148
|
-
NReProcessor(
|
|
149
|
-
re.compile(r'(?u)(\b[0-9]+[0-9:\']*(?<!\.\.)\s+(?!\.\.)[0-9,.:\'\s]*(?=[0-9]+)[0-9,.:\'])'),
|
|
150
|
-
lambda match: match.group(1).replace(" ", "") if match.group(1).count(" ") == 1 else match.group(1),
|
|
151
|
-
name="CM_spaces_in_numbers"),
|
|
152
|
-
|
|
153
|
-
# uppercase after dot
|
|
154
|
-
# NReProcessor(re.compile(r'(?u)((?<!(?=\s*[A-ZÀ-Ž-_0-9.]\s*))(?:[^.\s])+\.\s+)([a-zà-ž])'),
|
|
155
|
-
# lambda match: r'%s%s' % (match.group(1), match.group(2).upper()), name="CM_uppercase_after_dot"),
|
|
156
|
-
|
|
157
|
-
# remove double interpunction
|
|
158
|
-
NReProcessor(re.compile(r'(?u)(\s*[,!?])\s*([,.!?][,.!?\s]*)'),
|
|
159
|
-
lambda match: match.group(1).strip() + (" " if match.group(2).endswith(" ") else ""),
|
|
160
|
-
name="CM_double_interpunct"),
|
|
161
|
-
|
|
162
|
-
# remove spaces before punctuation; don't break spaced ellipses
|
|
163
|
-
NReProcessor(re.compile(r'(?u)(?:(?<=^)|(?<=\w)) +([!?.,](?![!?.,]| \.))'), r"\1", name="CM_punctuation_space"),
|
|
164
|
-
|
|
165
|
-
# add space after punctuation
|
|
166
|
-
NReProcessor(re.compile(r'(?u)(([^\s]*)([!?.,:])([A-zÀ-ž]{2,}))'),
|
|
167
|
-
lambda match: "%s%s %s" % (match.group(2), match.group(3), match.group(4)) if not get_tld(match.group(1), fail_silently=True, fix_protocol=True) else match.group(1),
|
|
168
|
-
name="CM_punctuation_space2"),
|
|
169
|
-
|
|
170
|
-
# fix lowercase I in english
|
|
171
|
-
NReProcessor(re.compile(r'(?u)(\b)i(\b)'), r"\1I\2", name="CM_EN_lowercase_i",
|
|
172
|
-
# supported=lambda p: p.language == ENGLISH),
|
|
173
|
-
),
|
|
174
|
-
]
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
class FixOCR(SubtitleTextModification):
|
|
178
|
-
identifier = "OCR_fixes"
|
|
179
|
-
description = "Fix common OCR issues"
|
|
180
|
-
exclusive = True
|
|
181
|
-
order = 10
|
|
182
|
-
data_dict = None
|
|
183
|
-
|
|
184
|
-
long_description = "Fix issues that happen when a subtitle gets converted from bitmap to text through OCR"
|
|
185
|
-
|
|
186
|
-
def __init__(self, language):
|
|
187
|
-
super(FixOCR, self).__init__()
|
|
188
|
-
data_dict = data.get(language)
|
|
189
|
-
if not data_dict:
|
|
190
|
-
# logger.debug("No SnR-data available for language %s", parent.language)
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
self.data_dict = data_dict
|
|
194
|
-
self.processors = self.get_processors()
|
|
195
|
-
|
|
196
|
-
def get_processors(self):
|
|
197
|
-
if not self.data_dict:
|
|
198
|
-
return []
|
|
199
|
-
|
|
200
|
-
return [
|
|
201
|
-
# remove broken HI tag colons (ANNOUNCER'., ". instead of :) after at least 3 uppercase chars
|
|
202
|
-
# don't modify stuff inside quotes
|
|
203
|
-
NReProcessor(re.compile(r'(?u)(^[^"\'’ʼ❜‘‛”“‟„]*(?<=[A-ZÀ-Ž]{3})[A-ZÀ-Ž-_\s0-9]+)'
|
|
204
|
-
r'(["\'’ʼ❜‘‛”“‟„]*[.,‚،⹁、;]+)(\s*)(?!["\'’ʼ❜‘‛”“‟„])'),
|
|
205
|
-
r"\1:\3", name="OCR_fix_HI_colons"),
|
|
206
|
-
# fix F'bla
|
|
207
|
-
NReProcessor(re.compile(r'(?u)(\bF)(\')([A-zÀ-ž]*\b)'), r"\1\3", name="OCR_fix_F"),
|
|
208
|
-
WholeLineProcessor(self.data_dict["WholeLines"], name="OCR_replace_line"),
|
|
209
|
-
MultipleWordReProcessor(self.data_dict["WholeWords"], name="OCR_replace_word"),
|
|
210
|
-
MultipleWordReProcessor(self.data_dict["BeginLines"], name="OCR_replace_beginline"),
|
|
211
|
-
MultipleWordReProcessor(self.data_dict["EndLines"], name="OCR_replace_endline"),
|
|
212
|
-
MultipleWordReProcessor(self.data_dict["PartialLines"], name="OCR_replace_partialline"),
|
|
213
|
-
MultipleLineProcessor(self.data_dict["PartialWordsAlways"], name="OCR_replace_partialwordsalways")
|
|
214
|
-
]
|
|
215
|
-
|
|
1
|
+
# MIT License
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2018 Hannes Tismer
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
#
|
|
23
|
+
#
|
|
24
|
+
# Copyright for portions of project Sub-Zero are held by Bram Walet, 2014 as part of project Subliminal.bundle.
|
|
25
|
+
# The original license is supplied below.
|
|
26
|
+
#
|
|
27
|
+
# The MIT License (MIT)
|
|
28
|
+
#
|
|
29
|
+
# Copyright (c) 2014 Bram Walet
|
|
30
|
+
#
|
|
31
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
32
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
33
|
+
# in the Software without restriction, including without limitation the rights
|
|
34
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
35
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
36
|
+
# furnished to do so, subject to the following conditions:
|
|
37
|
+
#
|
|
38
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
39
|
+
# copies or substantial portions of the Software.
|
|
40
|
+
#
|
|
41
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
42
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
43
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
44
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
45
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
46
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
47
|
+
# SOFTWARE.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
import re
|
|
51
|
+
|
|
52
|
+
from tld import get_tld
|
|
53
|
+
|
|
54
|
+
from Libraries.SubZero.dictionaries.data import data
|
|
55
|
+
from Libraries.SubZero.SubZero import (
|
|
56
|
+
MultipleLineProcessor,
|
|
57
|
+
MultipleWordReProcessor,
|
|
58
|
+
NReProcessor,
|
|
59
|
+
ReProcessor,
|
|
60
|
+
SubtitleTextModification,
|
|
61
|
+
WholeLineProcessor,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CommonFixes(SubtitleTextModification):
|
|
66
|
+
identifier = "common"
|
|
67
|
+
description = "Basic common fixes"
|
|
68
|
+
exclusive = True
|
|
69
|
+
order = 40
|
|
70
|
+
|
|
71
|
+
long_description = "Fix common and whitespace/punctuation issues in subtitles"
|
|
72
|
+
|
|
73
|
+
processors = [
|
|
74
|
+
# normalize hyphens
|
|
75
|
+
NReProcessor(re.compile(r'(?u)([‑‐﹘﹣])'), "-", name="CM_hyphens"),
|
|
76
|
+
|
|
77
|
+
# -- = em dash
|
|
78
|
+
NReProcessor(re.compile(r'(?u)(\w|\b|\s|^)(-\s?-{1,2})'), r"\1—", name="CM_multidash"),
|
|
79
|
+
|
|
80
|
+
# line = _/-/\s
|
|
81
|
+
NReProcessor(re.compile(r'(?u)(^\W*[-_.:<>~"\']+\W*$)'), "", name="CM_non_word_only"),
|
|
82
|
+
|
|
83
|
+
# remove >>
|
|
84
|
+
NReProcessor(re.compile(r'(?u)^\s?>>\s*'), "", name="CM_leading_crocodiles"),
|
|
85
|
+
|
|
86
|
+
# line = : text
|
|
87
|
+
NReProcessor(re.compile(r'(?u)(^\W*:\s*(?=\w+))'), "", name="CM_empty_colon_start"),
|
|
88
|
+
|
|
89
|
+
# fix music symbols
|
|
90
|
+
NReProcessor(re.compile(r'(?u)(^[-\s>~]*[*#¶]+\s+)|(\s*[*#¶]+\s*$)'),
|
|
91
|
+
lambda x: "♪ " if x.group(1) else " ♪",
|
|
92
|
+
name="CM_music_symbols"),
|
|
93
|
+
|
|
94
|
+
# '' = "
|
|
95
|
+
NReProcessor(re.compile(r'(?u)([\'’ʼ❜‘‛][\'’ʼ❜‘‛]+)'), '"', name="CM_double_apostrophe"),
|
|
96
|
+
|
|
97
|
+
# double quotes instead of single quotes inside words
|
|
98
|
+
NReProcessor(re.compile(r'(?u)([A-zÀ-ž])"([A-zÀ-ž])'), r"\1'\2", name="CM_double_as_single"),
|
|
99
|
+
|
|
100
|
+
# normalize quotes
|
|
101
|
+
NReProcessor(re.compile(r'(?u)(\s*["”“‟„])\s*(["”“‟„]["”“‟„\s]*)'),
|
|
102
|
+
lambda match: '"' + (" " if match.group(2).endswith(" ") else ""),
|
|
103
|
+
name="CM_normalize_quotes"),
|
|
104
|
+
|
|
105
|
+
# normalize single quotes
|
|
106
|
+
NReProcessor(re.compile(r'(?u)([\'’ʼ❜‘‛])'), "'", name="CM_normalize_squotes"),
|
|
107
|
+
|
|
108
|
+
# remove leading ...
|
|
109
|
+
NReProcessor(re.compile(r'(?u)^\.\.\.[\s]*'), "", name="CM_leading_ellipsis"),
|
|
110
|
+
|
|
111
|
+
# remove "downloaded from" tags
|
|
112
|
+
NReProcessor(re.compile(r'(?ui).+downloaded\s+from.+'), "", name="CM_crap"),
|
|
113
|
+
|
|
114
|
+
# no space after ellipsis
|
|
115
|
+
NReProcessor(re.compile(r'(?u)\.\.\.(?![\s.,!?\'"])(?!$)'), "... ", name="CM_ellipsis_no_space"),
|
|
116
|
+
|
|
117
|
+
# no space before spaced ellipsis
|
|
118
|
+
NReProcessor(re.compile(r'(?u)(?<=[^\s])(?<!\s)\. \. \.'), " . . .", name="CM_ellipsis_no_space2"),
|
|
119
|
+
|
|
120
|
+
# multiple spaces
|
|
121
|
+
NReProcessor(re.compile(r'(?u)[\s]{2,}'), " ", name="CM_multiple_spaces"),
|
|
122
|
+
|
|
123
|
+
# more than 3 dots
|
|
124
|
+
NReProcessor(re.compile(r'(?u)\.{3,}'), "...", name="CM_dots"),
|
|
125
|
+
|
|
126
|
+
# no space after starting dash
|
|
127
|
+
NReProcessor(re.compile(r'(?u)^-(?![\s-])'), "- ", name="CM_dash_space"),
|
|
128
|
+
|
|
129
|
+
# remove starting spaced dots (not matching ellipses)
|
|
130
|
+
NReProcessor(re.compile(r'(?u)^(?!\s?(\.\s\.\s\.)|(\s?\.{3}))(?=\.+\s+)[\s.]*'), "",
|
|
131
|
+
name="CM_starting_spacedots"),
|
|
132
|
+
|
|
133
|
+
# space missing before doublequote
|
|
134
|
+
ReProcessor(re.compile(r'(?u)(?<!^)(?<![\s(\["])("[^"]+")'), r' \1', name="CM_space_before_dblquote"),
|
|
135
|
+
|
|
136
|
+
# space missing after doublequote
|
|
137
|
+
ReProcessor(re.compile(r'(?u)("[^"\s][^"]+")([^\s.,!?)\]]+)'), r"\1 \2", name="CM_space_after_dblquote"),
|
|
138
|
+
|
|
139
|
+
# space before ending doublequote?
|
|
140
|
+
|
|
141
|
+
# replace uppercase I with lowercase L in words
|
|
142
|
+
NReProcessor(re.compile(r'(?u)([a-zà-ž]+)(I+)'),
|
|
143
|
+
lambda match: r'%s%s' % (match.group(1), "l" * len(match.group(2))),
|
|
144
|
+
name="CM_uppercase_i_in_word"),
|
|
145
|
+
|
|
146
|
+
# fix spaces in numbers (allows for punctuation: ,.:' (comma/dot only fixed if after space, those may be
|
|
147
|
+
# countdowns otherwise); don't break up ellipses
|
|
148
|
+
NReProcessor(
|
|
149
|
+
re.compile(r'(?u)(\b[0-9]+[0-9:\']*(?<!\.\.)\s+(?!\.\.)[0-9,.:\'\s]*(?=[0-9]+)[0-9,.:\'])'),
|
|
150
|
+
lambda match: match.group(1).replace(" ", "") if match.group(1).count(" ") == 1 else match.group(1),
|
|
151
|
+
name="CM_spaces_in_numbers"),
|
|
152
|
+
|
|
153
|
+
# uppercase after dot
|
|
154
|
+
# NReProcessor(re.compile(r'(?u)((?<!(?=\s*[A-ZÀ-Ž-_0-9.]\s*))(?:[^.\s])+\.\s+)([a-zà-ž])'),
|
|
155
|
+
# lambda match: r'%s%s' % (match.group(1), match.group(2).upper()), name="CM_uppercase_after_dot"),
|
|
156
|
+
|
|
157
|
+
# remove double interpunction
|
|
158
|
+
NReProcessor(re.compile(r'(?u)(\s*[,!?])\s*([,.!?][,.!?\s]*)'),
|
|
159
|
+
lambda match: match.group(1).strip() + (" " if match.group(2).endswith(" ") else ""),
|
|
160
|
+
name="CM_double_interpunct"),
|
|
161
|
+
|
|
162
|
+
# remove spaces before punctuation; don't break spaced ellipses
|
|
163
|
+
NReProcessor(re.compile(r'(?u)(?:(?<=^)|(?<=\w)) +([!?.,](?![!?.,]| \.))'), r"\1", name="CM_punctuation_space"),
|
|
164
|
+
|
|
165
|
+
# add space after punctuation
|
|
166
|
+
NReProcessor(re.compile(r'(?u)(([^\s]*)([!?.,:])([A-zÀ-ž]{2,}))'),
|
|
167
|
+
lambda match: "%s%s %s" % (match.group(2), match.group(3), match.group(4)) if not get_tld(match.group(1), fail_silently=True, fix_protocol=True) else match.group(1),
|
|
168
|
+
name="CM_punctuation_space2"),
|
|
169
|
+
|
|
170
|
+
# fix lowercase I in english
|
|
171
|
+
NReProcessor(re.compile(r'(?u)(\b)i(\b)'), r"\1I\2", name="CM_EN_lowercase_i",
|
|
172
|
+
# supported=lambda p: p.language == ENGLISH),
|
|
173
|
+
),
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class FixOCR(SubtitleTextModification):
|
|
178
|
+
identifier = "OCR_fixes"
|
|
179
|
+
description = "Fix common OCR issues"
|
|
180
|
+
exclusive = True
|
|
181
|
+
order = 10
|
|
182
|
+
data_dict = None
|
|
183
|
+
|
|
184
|
+
long_description = "Fix issues that happen when a subtitle gets converted from bitmap to text through OCR"
|
|
185
|
+
|
|
186
|
+
def __init__(self, language):
|
|
187
|
+
super(FixOCR, self).__init__()
|
|
188
|
+
data_dict = data.get(language)
|
|
189
|
+
if not data_dict:
|
|
190
|
+
# logger.debug("No SnR-data available for language %s", parent.language)
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
self.data_dict = data_dict
|
|
194
|
+
self.processors = self.get_processors()
|
|
195
|
+
|
|
196
|
+
def get_processors(self):
|
|
197
|
+
if not self.data_dict:
|
|
198
|
+
return []
|
|
199
|
+
|
|
200
|
+
return [
|
|
201
|
+
# remove broken HI tag colons (ANNOUNCER'., ". instead of :) after at least 3 uppercase chars
|
|
202
|
+
# don't modify stuff inside quotes
|
|
203
|
+
NReProcessor(re.compile(r'(?u)(^[^"\'’ʼ❜‘‛”“‟„]*(?<=[A-ZÀ-Ž]{3})[A-ZÀ-Ž-_\s0-9]+)'
|
|
204
|
+
r'(["\'’ʼ❜‘‛”“‟„]*[.,‚،⹁、;]+)(\s*)(?!["\'’ʼ❜‘‛”“‟„])'),
|
|
205
|
+
r"\1:\3", name="OCR_fix_HI_colons"),
|
|
206
|
+
# fix F'bla
|
|
207
|
+
NReProcessor(re.compile(r'(?u)(\bF)(\')([A-zÀ-ž]*\b)'), r"\1\3", name="OCR_fix_F"),
|
|
208
|
+
WholeLineProcessor(self.data_dict["WholeLines"], name="OCR_replace_line"),
|
|
209
|
+
MultipleWordReProcessor(self.data_dict["WholeWords"], name="OCR_replace_word"),
|
|
210
|
+
MultipleWordReProcessor(self.data_dict["BeginLines"], name="OCR_replace_beginline"),
|
|
211
|
+
MultipleWordReProcessor(self.data_dict["EndLines"], name="OCR_replace_endline"),
|
|
212
|
+
MultipleWordReProcessor(self.data_dict["PartialLines"], name="OCR_replace_partialline"),
|
|
213
|
+
MultipleLineProcessor(self.data_dict["PartialWordsAlways"], name="OCR_replace_partialwordsalways")
|
|
214
|
+
]
|
|
215
|
+
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
# pgs2srt
|
|
2
|
-
|
|
3
|
-
Uses [pgsreader](https://github.com/EzraBC/pgsreader) and [pyteseract](https://pypi.org/project/pytesseract/) to convert image based pgs subtitles files (.sup) to text based subrip (.srt) files.
|
|
4
|
-
|
|
5
|
-
## Requirements
|
|
6
|
-
Python3, pip3, and Tesseract
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
* Run ```git clone https://github.com/PimvanderLoos/pgs2srt.git```
|
|
10
|
-
* Inside the repo folder, run ```pip3 install -r requirements.txt```
|
|
11
|
-
* In your .bashrc or .zshrc add ```alias pgs2srt='<absolute path to repo>/pgs2srt.py'```
|
|
12
|
-
|
|
13
|
-
## How to run
|
|
14
|
-
|
|
15
|
-
pgs2srt <pgs filename>.sup
|
|
16
|
-
|
|
17
|
-
## Improving accuracy
|
|
18
|
-
On Debian and Ubuntu, the default trained models files for Tesseract are from the [fast](https://github.com/tesseract-ocr/tessdata_fast) set. While these are a bit faster than other options, this comes at the cost of accuracy. If you want higher accuracy, I'd recommend using either the [legacy](https://github.com/tesseract-ocr/tessdata) or the [best](https://github.com/tesseract-ocr/tessdata_best) trained models. Note that the fast and best options only support the LSTM OCR Engine Mode (oem 1).
|
|
19
|
-
|
|
20
|
-
## Caveats
|
|
21
|
-
|
|
22
|
-
This is in no way a perfect converter, and tesseract will make incorrect interpretations of characters. Extremely alpha, issues, pull requests and suggestions welcome!
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
## Credits
|
|
26
|
-
This project uses the common + OCR fixes developed by [Sub-Zero.bundle](https://github.com/pannal/Sub-Zero.bundle).
|
|
1
|
+
# pgs2srt
|
|
2
|
+
|
|
3
|
+
Uses [pgsreader](https://github.com/EzraBC/pgsreader) and [pyteseract](https://pypi.org/project/pytesseract/) to convert image based pgs subtitles files (.sup) to text based subrip (.srt) files.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
Python3, pip3, and Tesseract
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
* Run ```git clone https://github.com/PimvanderLoos/pgs2srt.git```
|
|
10
|
+
* Inside the repo folder, run ```pip3 install -r requirements.txt```
|
|
11
|
+
* In your .bashrc or .zshrc add ```alias pgs2srt='<absolute path to repo>/pgs2srt.py'```
|
|
12
|
+
|
|
13
|
+
## How to run
|
|
14
|
+
|
|
15
|
+
pgs2srt <pgs filename>.sup
|
|
16
|
+
|
|
17
|
+
## Improving accuracy
|
|
18
|
+
On Debian and Ubuntu, the default trained models files for Tesseract are from the [fast](https://github.com/tesseract-ocr/tessdata_fast) set. While these are a bit faster than other options, this comes at the cost of accuracy. If you want higher accuracy, I'd recommend using either the [legacy](https://github.com/tesseract-ocr/tessdata) or the [best](https://github.com/tesseract-ocr/tessdata_best) trained models. Note that the fast and best options only support the LSTM OCR Engine Mode (oem 1).
|
|
19
|
+
|
|
20
|
+
## Caveats
|
|
21
|
+
|
|
22
|
+
This is in no way a perfect converter, and tesseract will make incorrect interpretations of characters. Extremely alpha, issues, pull requests and suggestions welcome!
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## Credits
|
|
26
|
+
This project uses the common + OCR fixes developed by [Sub-Zero.bundle](https://github.com/pannal/Sub-Zero.bundle).
|