easyrip 4.3.3__py3-none-any.whl → 4.5.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.
- easyrip/__init__.py +5 -1
- easyrip/__main__.py +1 -0
- easyrip/easyrip_command.py +15 -46
- easyrip/easyrip_main.py +18 -10
- easyrip/global_val.py +1 -1
- easyrip/ripper/param.py +462 -0
- easyrip/ripper/ripper.py +86 -476
- easyrip/ripper/sub_and_font/__init__.py +10 -0
- easyrip/ripper/{font_subset → sub_and_font}/font.py +39 -11
- easyrip/ripper/{font_subset → sub_and_font}/subset.py +28 -14
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/METADATA +3 -3
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/RECORD +17 -17
- easyrip/ripper/__init__.py +0 -10
- easyrip/ripper/font_subset/__init__.py +0 -7
- /easyrip/ripper/{font_subset → sub_and_font}/ass.py +0 -0
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/WHEEL +0 -0
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/entry_points.txt +0 -0
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/licenses/LICENSE +0 -0
- {easyrip-4.3.3.dist-info → easyrip-4.5.0.dist-info}/top_level.txt +0 -0
|
@@ -40,7 +40,13 @@ class Font:
|
|
|
40
40
|
self.font.close()
|
|
41
41
|
|
|
42
42
|
|
|
43
|
-
def load_fonts(
|
|
43
|
+
def load_fonts(
|
|
44
|
+
path: str | Path,
|
|
45
|
+
*,
|
|
46
|
+
lazy: bool = True,
|
|
47
|
+
strict: bool = False,
|
|
48
|
+
) -> list[Font]:
|
|
49
|
+
"""strict: Skip UnicodeDecodeError font file"""
|
|
44
50
|
if isinstance(path, str):
|
|
45
51
|
path = Path(path)
|
|
46
52
|
|
|
@@ -59,7 +65,8 @@ def load_fonts(path: str | Path, lazy: bool = True) -> list[Font]:
|
|
|
59
65
|
if suffix == ".ttc"
|
|
60
66
|
else [TTFont(file=file, lazy=lazy)]
|
|
61
67
|
):
|
|
62
|
-
|
|
68
|
+
skip_this_font: bool = False
|
|
69
|
+
table_name: table__n_a_m_e | None = font.get("name")
|
|
63
70
|
|
|
64
71
|
if table_name is None:
|
|
65
72
|
log.warning(f"No 'name' table found in font {file}")
|
|
@@ -76,7 +83,16 @@ def load_fonts(path: str | Path, lazy: bool = True) -> list[Font]:
|
|
|
76
83
|
if name_id not in {1, 2}:
|
|
77
84
|
continue
|
|
78
85
|
|
|
79
|
-
|
|
86
|
+
try:
|
|
87
|
+
name_str: str = record.toUnicode()
|
|
88
|
+
except UnicodeDecodeError as e:
|
|
89
|
+
error_text = f"Unicode decode error in font \"{file}\": {e}: '{record.toUnicode('replace')}'. Skip this {'font' if strict else 'name record'}."
|
|
90
|
+
if strict:
|
|
91
|
+
log.error(error_text, is_format=False)
|
|
92
|
+
skip_this_font = True
|
|
93
|
+
break
|
|
94
|
+
log.warning(error_text, is_format=False)
|
|
95
|
+
continue
|
|
80
96
|
|
|
81
97
|
match name_id:
|
|
82
98
|
case 1: # Font Family Name
|
|
@@ -94,6 +110,9 @@ def load_fonts(path: str | Path, lazy: bool = True) -> list[Font]:
|
|
|
94
110
|
case "italic" | "oblique":
|
|
95
111
|
is_italic = True
|
|
96
112
|
|
|
113
|
+
if skip_this_font:
|
|
114
|
+
continue
|
|
115
|
+
|
|
97
116
|
if not res_font.familys:
|
|
98
117
|
log.warning(f"Font {file} has no family names. Skip this font")
|
|
99
118
|
continue
|
|
@@ -121,16 +140,18 @@ def load_fonts(path: str | Path, lazy: bool = True) -> list[Font]:
|
|
|
121
140
|
res_font_list.append(res_font)
|
|
122
141
|
|
|
123
142
|
except TTLibError as e:
|
|
124
|
-
log.
|
|
125
|
-
except UnicodeDecodeError as e:
|
|
126
|
-
log.warning(f"Unicode decode error for font {file}: {e}")
|
|
143
|
+
log.error(f'Error loading font file "{file}": {e}')
|
|
127
144
|
except Exception as e:
|
|
128
145
|
log.error(f"Unexpected error for font {file}: {e}")
|
|
129
146
|
|
|
130
147
|
return res_font_list
|
|
131
148
|
|
|
132
149
|
|
|
133
|
-
def load_windows_fonts(
|
|
150
|
+
def load_windows_fonts(
|
|
151
|
+
*,
|
|
152
|
+
lazy: bool = True,
|
|
153
|
+
strict: bool = False,
|
|
154
|
+
) -> list[Font]:
|
|
134
155
|
paths: tuple[str, ...] = (
|
|
135
156
|
os.path.join(os.environ["SYSTEMROOT"], "Fonts"),
|
|
136
157
|
os.path.join(os.environ["LOCALAPPDATA"], "Microsoft/Windows/Fonts"),
|
|
@@ -138,7 +159,7 @@ def load_windows_fonts(lazy: bool = True) -> list[Font]:
|
|
|
138
159
|
|
|
139
160
|
return list(
|
|
140
161
|
itertools.chain.from_iterable(
|
|
141
|
-
load_fonts(path
|
|
162
|
+
load_fonts(path, lazy=lazy, strict=strict) for path in paths
|
|
142
163
|
)
|
|
143
164
|
)
|
|
144
165
|
|
|
@@ -149,7 +170,9 @@ def subset_font(font: Font, subset_str: str, affix: str) -> tuple[TTFont, bool]:
|
|
|
149
170
|
# 检查哪些字符不存在于字体中
|
|
150
171
|
try:
|
|
151
172
|
cmap = subset_font.getBestCmap()
|
|
152
|
-
|
|
173
|
+
if cmap is None:
|
|
174
|
+
raise Exception("cmap is None")
|
|
175
|
+
available_chars = set(map(chr, cmap))
|
|
153
176
|
except Exception as e:
|
|
154
177
|
raise Font_error("Can not read best cmap from '{}'", font.pathname) from e
|
|
155
178
|
input_chars = set(subset_str)
|
|
@@ -191,8 +214,13 @@ def subset_font(font: Font, subset_str: str, affix: str) -> tuple[TTFont, bool]:
|
|
|
191
214
|
# 修改 Name Record
|
|
192
215
|
affix_ascii = affix.encode("ascii")
|
|
193
216
|
affix_utf16be = affix.encode("utf-16-be")
|
|
194
|
-
table_name: table__n_a_m_e = font.font.get("name")
|
|
195
|
-
subset_table_name: table__n_a_m_e = subset_font.get("name")
|
|
217
|
+
table_name: table__n_a_m_e | None = font.font.get("name")
|
|
218
|
+
subset_table_name: table__n_a_m_e | None = subset_font.get("name")
|
|
219
|
+
|
|
220
|
+
# 这两个都是复制的,所以不可能是 None
|
|
221
|
+
assert table_name is not None
|
|
222
|
+
assert subset_table_name is not None
|
|
223
|
+
|
|
196
224
|
subset_table_name.names = list[NameRecord]() # 重写 name table
|
|
197
225
|
for record in table_name.names:
|
|
198
226
|
name_id = int(record.nameID)
|
|
@@ -140,22 +140,32 @@ def subset(
|
|
|
140
140
|
for tag, value in re.findall(
|
|
141
141
|
r"\\\s*(fn|b(?![a-zA-Z])|i(?![a-zA-Z])|r)([^\\}]*)", text
|
|
142
142
|
):
|
|
143
|
+
assert isinstance(tag, str) and isinstance(value, str)
|
|
144
|
+
|
|
145
|
+
proc_value = value.strip()
|
|
146
|
+
if proc_value.startswith("("):
|
|
147
|
+
proc_value = proc_value[1:]
|
|
148
|
+
if (_index := proc_value.find(")")) != -1:
|
|
149
|
+
proc_value = proc_value[:_index]
|
|
150
|
+
proc_value = proc_value.strip()
|
|
151
|
+
|
|
143
152
|
match tag:
|
|
144
153
|
case "fn":
|
|
145
|
-
tag_fn =
|
|
154
|
+
tag_fn = proc_value
|
|
146
155
|
case "b":
|
|
147
|
-
tag_bold =
|
|
156
|
+
tag_bold = proc_value
|
|
148
157
|
case "i":
|
|
149
|
-
tag_italic =
|
|
158
|
+
tag_italic = proc_value
|
|
150
159
|
case "r":
|
|
151
|
-
if
|
|
152
|
-
|
|
160
|
+
r_value = proc_value if "(" in value else value.rstrip()
|
|
161
|
+
if r_value in style__font_sign:
|
|
162
|
+
current_font_sign = style__font_sign[r_value]
|
|
153
163
|
else:
|
|
154
164
|
# 空为还原样式, 非样式表内样式名效果同空, 但发出不规范警告
|
|
155
165
|
current_font_sign = default_font_sign
|
|
156
|
-
if
|
|
166
|
+
if r_value != "":
|
|
157
167
|
log.warning(
|
|
158
|
-
"The \\r style '{}' not in Styles",
|
|
168
|
+
"The \\r style '{}' not in Styles", r_value
|
|
159
169
|
)
|
|
160
170
|
|
|
161
171
|
new_fontname: str = current_font_sign[0]
|
|
@@ -164,12 +174,12 @@ def subset(
|
|
|
164
174
|
new_bold, new_italic = current_font_sign[1].value
|
|
165
175
|
|
|
166
176
|
if tag_fn is not None:
|
|
167
|
-
match
|
|
177
|
+
match tag_fn:
|
|
168
178
|
case "":
|
|
169
179
|
new_fontname = default_font_sign[0]
|
|
170
180
|
case _:
|
|
171
|
-
_is_vertical: bool =
|
|
172
|
-
new_fontname =
|
|
181
|
+
_is_vertical: bool = tag_fn.startswith("@")
|
|
182
|
+
new_fontname = tag_fn[1:] if _is_vertical else tag_fn
|
|
173
183
|
|
|
174
184
|
# 修改
|
|
175
185
|
text = text.replace(
|
|
@@ -178,7 +188,7 @@ def subset(
|
|
|
178
188
|
)
|
|
179
189
|
|
|
180
190
|
if tag_bold is not None:
|
|
181
|
-
match tag_bold
|
|
191
|
+
match tag_bold:
|
|
182
192
|
case "":
|
|
183
193
|
new_bold = default_font_sign[1].value[0]
|
|
184
194
|
case "0":
|
|
@@ -195,7 +205,7 @@ def subset(
|
|
|
195
205
|
return_res = not strict
|
|
196
206
|
|
|
197
207
|
if tag_italic is not None:
|
|
198
|
-
match tag_italic
|
|
208
|
+
match tag_italic:
|
|
199
209
|
case "":
|
|
200
210
|
new_italic = default_font_sign[1].value[1]
|
|
201
211
|
case "0":
|
|
@@ -272,9 +282,9 @@ def subset(
|
|
|
272
282
|
# 加载 Font
|
|
273
283
|
fonts: Final[list[Font]] = []
|
|
274
284
|
for _path in font_path_list:
|
|
275
|
-
fonts.extend(load_fonts(_path))
|
|
285
|
+
fonts.extend(load_fonts(_path, strict=strict))
|
|
276
286
|
if use_win_font:
|
|
277
|
-
fonts.extend(load_windows_fonts())
|
|
287
|
+
fonts.extend(load_windows_fonts(strict=strict))
|
|
278
288
|
|
|
279
289
|
font_sign__font: dict[tuple[str, Font_type], Font] = {}
|
|
280
290
|
for _font in fonts:
|
|
@@ -362,6 +372,10 @@ def subset(
|
|
|
362
372
|
f"( {key[0]} / {key[1].name} ){mapping_res}",
|
|
363
373
|
deep=(strict and bool(mapping_res)),
|
|
364
374
|
)
|
|
375
|
+
log.debug(
|
|
376
|
+
f"{_font.pathname}: {_font.familys} {_font.font_type.name}",
|
|
377
|
+
is_format=False,
|
|
378
|
+
)
|
|
365
379
|
|
|
366
380
|
# 子集化字体
|
|
367
381
|
for key, val in font__subset_str.items():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: easyrip
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.5.0
|
|
4
4
|
Author: op200
|
|
5
5
|
License-Expression: AGPL-3.0-or-later
|
|
6
6
|
Project-URL: Homepage, https://github.com/op200/EasyRip
|
|
@@ -21,8 +21,8 @@ Requires-Python: >=3.12
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: prompt-toolkit>=3.0.52
|
|
24
|
-
Requires-Dist: fonttools>=4.61.
|
|
25
|
-
Requires-Dist: pycryptodome>=3.
|
|
24
|
+
Requires-Dist: fonttools>=4.61.1
|
|
25
|
+
Requires-Dist: pycryptodome>=3.23.0
|
|
26
26
|
Dynamic: license-file
|
|
27
27
|
|
|
28
28
|
# Easy Rip
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
easyrip/__init__.py,sha256=
|
|
2
|
-
easyrip/__main__.py,sha256=
|
|
3
|
-
easyrip/easyrip_command.py,sha256=
|
|
1
|
+
easyrip/__init__.py,sha256=PIvSPDgswsIkWL4dsCe87knnxKmtvcrWYzmqAwZix_M,765
|
|
2
|
+
easyrip/__main__.py,sha256=ndKSOQpWOUtpVf009yqX-9vEiEjOgFDye0re45_PfQQ,4454
|
|
3
|
+
easyrip/easyrip_command.py,sha256=YnwtrAh7FtN7Uk8R_Fupn96OTeWtzdCYN0p5rEFe91o,27833
|
|
4
4
|
easyrip/easyrip_log.py,sha256=0V5wBwbqWt56w_NHoLmQmkTHPnPLkYZCAbhDSYnLnDw,15611
|
|
5
|
-
easyrip/easyrip_main.py,sha256=
|
|
5
|
+
easyrip/easyrip_main.py,sha256=39a1cSnQUnNplX5rVTG1ECoo0_RCpQyylPu1uhArnZc,43886
|
|
6
6
|
easyrip/easyrip_prompt.py,sha256=A5S7ybeJSGFkCmwdJ9TCQ_-lde7NWgkbFytZ2KnvkWI,2145
|
|
7
|
-
easyrip/global_val.py,sha256=
|
|
7
|
+
easyrip/global_val.py,sha256=yzNIoY-_F1mkIsk39lsW7iNFbqBAB88HMg-WbE7Jg-E,773
|
|
8
8
|
easyrip/utils.py,sha256=YM8gaKon-9DLt5llF-7-TE0JqDpKZrKGj7oRScLFatU,6322
|
|
9
9
|
easyrip/easyrip_config/config.py,sha256=9uskiGIpYLuS-vjzNASZlhdWLWXkEVxtSjODxcZU3pc,7935
|
|
10
10
|
easyrip/easyrip_config/config_key.py,sha256=wANVusz9kNqsYJUvXM7DUQn6k_G6EO2VWTHWh9dOifw,394
|
|
@@ -16,16 +16,16 @@ easyrip/easyrip_mlang/translator.py,sha256=Vg0S0p2rpMNAy3LHTdK7qKFdkPEXlOoCCXcaH
|
|
|
16
16
|
easyrip/easyrip_web/__init__.py,sha256=tMyEeaSGeEJjND7MF0MBv9aDiDgaO3MOnppwxA70U2c,177
|
|
17
17
|
easyrip/easyrip_web/http_server.py,sha256=iyulCAFQrJlz86Lrr-Dm3fhOnNCf79Bp6fVHhr0ephY,8350
|
|
18
18
|
easyrip/easyrip_web/third_party_api.py,sha256=umj-QsfOa0IM60Ic2pXigVfnGfAiiC95fJSXQ-WFpJA,4419
|
|
19
|
-
easyrip/ripper/__init__.py,sha256=o5gj8QRvkuVc0S9jbRjVOWXpLAaQKC0-n-o6Zx9Dowo,171
|
|
20
19
|
easyrip/ripper/media_info.py,sha256=mQq_vbQ7S9fWpb39HLkoZlAL-pqNfwxewv6X776Nf50,5078
|
|
21
|
-
easyrip/ripper/
|
|
22
|
-
easyrip/ripper/
|
|
23
|
-
easyrip/ripper/
|
|
24
|
-
easyrip/ripper/
|
|
25
|
-
easyrip/ripper/
|
|
26
|
-
easyrip
|
|
27
|
-
easyrip-4.
|
|
28
|
-
easyrip-4.
|
|
29
|
-
easyrip-4.
|
|
30
|
-
easyrip-4.
|
|
31
|
-
easyrip-4.
|
|
20
|
+
easyrip/ripper/param.py,sha256=x11G7AsU-1Ol37-psKNo8AtjKDdD8YPlXeNwJSbhZxw,11082
|
|
21
|
+
easyrip/ripper/ripper.py,sha256=Ru3FI7c6toMEm1qgt_5XneeIYHTTv269nS6-Dmv1f6Y,50167
|
|
22
|
+
easyrip/ripper/sub_and_font/__init__.py,sha256=cBT7mxL7RRFaJXFPXuZ7RT-YK6FbnanaU5v6U9BOquw,153
|
|
23
|
+
easyrip/ripper/sub_and_font/ass.py,sha256=eGi1eIDWAV1Ti_BYIAcAMwrAlXJ5f_zGYte3nNu4PeE,25532
|
|
24
|
+
easyrip/ripper/sub_and_font/font.py,sha256=pzRtMrcL3ATFOMM5nsJQqSBbZtrnRodIgxLkjHai7kg,8075
|
|
25
|
+
easyrip/ripper/sub_and_font/subset.py,sha256=VsFYTFuVWXW9ltkqWZIiwOIh-nGDKmW1tUv3oi5kpWw,17815
|
|
26
|
+
easyrip-4.5.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
27
|
+
easyrip-4.5.0.dist-info/METADATA,sha256=10d52t-vOhqDgakGdsn0_0QLCrnMSuoMvQ9rUOwsraY,3506
|
|
28
|
+
easyrip-4.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
29
|
+
easyrip-4.5.0.dist-info/entry_points.txt,sha256=D6GBMMTzZ-apgX76KyZ6jxMmIFqGYwU9neeLLni_qKI,49
|
|
30
|
+
easyrip-4.5.0.dist-info/top_level.txt,sha256=kuEteBXm-Gf90jRQgH3-fTo-Z-Q6czSuUEqY158H4Ww,8
|
|
31
|
+
easyrip-4.5.0.dist-info/RECORD,,
|
easyrip/ripper/__init__.py
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|