jmcomic 2.1.15__py3-none-any.whl → 2.1.17__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.
- jmcomic/__init__.py +1 -1
- jmcomic/jm_client_impl.py +6 -3
- jmcomic/jm_client_interface.py +3 -3
- jmcomic/jm_config.py +35 -4
- jmcomic/jm_entity.py +5 -5
- jmcomic/jm_option.py +7 -4
- jmcomic/jm_toolkit.py +26 -9
- {jmcomic-2.1.15.dist-info → jmcomic-2.1.17.dist-info}/METADATA +1 -1
- jmcomic-2.1.17.dist-info/RECORD +14 -0
- jmcomic-2.1.15.dist-info/RECORD +0 -14
- {jmcomic-2.1.15.dist-info → jmcomic-2.1.17.dist-info}/LICENSE +0 -0
- {jmcomic-2.1.15.dist-info → jmcomic-2.1.17.dist-info}/WHEEL +0 -0
- {jmcomic-2.1.15.dist-info → jmcomic-2.1.17.dist-info}/top_level.txt +0 -0
jmcomic/__init__.py
CHANGED
jmcomic/jm_client_impl.py
CHANGED
|
@@ -143,7 +143,7 @@ class AbstractJmClient(
|
|
|
143
143
|
def fallback(self, request, url, domain_index, retry_count, **kwargs):
|
|
144
144
|
msg = f"请求重试全部失败: [{url}], {self.domain_list}"
|
|
145
145
|
jm_debug('req.fallback', msg)
|
|
146
|
-
raise
|
|
146
|
+
raise JmModuleConfig.exception(msg)
|
|
147
147
|
|
|
148
148
|
|
|
149
149
|
# 基于网页实现的JmClient
|
|
@@ -216,7 +216,7 @@ class JmHtmlClient(AbstractJmClient):
|
|
|
216
216
|
)
|
|
217
217
|
|
|
218
218
|
if resp.status_code != 301:
|
|
219
|
-
raise
|
|
219
|
+
raise JmModuleConfig.exception(f'登录失败,状态码为{resp.status_code}')
|
|
220
220
|
|
|
221
221
|
if refresh_client_cookies is True:
|
|
222
222
|
self['cookies'] = resp.cookies
|
|
@@ -251,7 +251,7 @@ class JmHtmlClient(AbstractJmClient):
|
|
|
251
251
|
+ (f"响应文本=[{resp.text}]" if len(resp.text) < 200 else
|
|
252
252
|
f'响应文本过长(len={len(resp.text)}),不打印'
|
|
253
253
|
)
|
|
254
|
-
raise
|
|
254
|
+
raise JmModuleConfig.exception(msg)
|
|
255
255
|
|
|
256
256
|
def get_jm_image(self, img_url) -> JmImageResp:
|
|
257
257
|
|
|
@@ -418,6 +418,9 @@ class JmApiClient(AbstractJmClient):
|
|
|
418
418
|
"accept-encoding": "gzip",
|
|
419
419
|
}, key_ts
|
|
420
420
|
|
|
421
|
+
def debug_topic_request(self):
|
|
422
|
+
return 'api'
|
|
423
|
+
|
|
421
424
|
|
|
422
425
|
class AsyncSaveImageClient(JmImageClient):
|
|
423
426
|
|
jmcomic/jm_client_interface.py
CHANGED
|
@@ -23,13 +23,13 @@ class JmResp(CommonResp):
|
|
|
23
23
|
class JmImageResp(JmResp):
|
|
24
24
|
|
|
25
25
|
def json(self, **kwargs) -> Dict:
|
|
26
|
-
raise
|
|
26
|
+
raise NotImplementedError
|
|
27
27
|
|
|
28
28
|
def require_success(self):
|
|
29
29
|
if self.is_success:
|
|
30
30
|
return
|
|
31
31
|
|
|
32
|
-
raise
|
|
32
|
+
raise JmModuleConfig.exception(self.get_error_msg())
|
|
33
33
|
|
|
34
34
|
def get_error_msg(self):
|
|
35
35
|
msg = f'禁漫图片获取失败: [{self.url}]'
|
|
@@ -68,7 +68,7 @@ class JmApiResp(JmResp):
|
|
|
68
68
|
@classmethod
|
|
69
69
|
def wrap(cls, resp, key_ts):
|
|
70
70
|
if isinstance(resp, JmApiResp):
|
|
71
|
-
raise
|
|
71
|
+
raise JmModuleConfig.exception('重复包装')
|
|
72
72
|
|
|
73
73
|
return cls(resp, key_ts)
|
|
74
74
|
|
jmcomic/jm_config.py
CHANGED
|
@@ -17,11 +17,19 @@ def default_postman_constructor(session, **kwargs):
|
|
|
17
17
|
return Postmans.new_postman(**kwargs)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
def default_raise_regex_error(msg, *_args, **_kwargs):
|
|
21
|
+
raise JmModuleConfig.exception(msg)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class JmcomicException(Exception):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
20
28
|
class JmModuleConfig:
|
|
21
29
|
# 网站相关
|
|
22
30
|
PROT = "https://"
|
|
23
31
|
JM_REDIRECT_URL = f'{PROT}jm365.work/3YeBdF' # 永久網域,怕走失的小伙伴收藏起来
|
|
24
|
-
JM_PUB_URL = f'{PROT}
|
|
32
|
+
JM_PUB_URL = f'{PROT}jmcomic.ltd'
|
|
25
33
|
JM_CDN_IMAGE_URL_TEMPLATE = PROT + 'cdn-msp.{domain}/media/photos/{photo_id}/{index:05}{suffix}' # index 从1开始
|
|
26
34
|
JM_IMAGE_SUFFIX = ['.jpg', '.webp', '.png', '.gif']
|
|
27
35
|
|
|
@@ -56,12 +64,17 @@ class JmModuleConfig:
|
|
|
56
64
|
CLASS_OPTION = None
|
|
57
65
|
CLASS_ALBUM = None
|
|
58
66
|
CLASS_PHOTO = None
|
|
67
|
+
CLASS_IMAGE = None
|
|
59
68
|
CLASS_CLIENT_IMPL = {}
|
|
69
|
+
CLASS_EXCEPTION = None
|
|
60
70
|
|
|
61
71
|
# 执行debug的函数
|
|
62
72
|
debug_executor = default_jm_debug
|
|
63
73
|
# postman构造函数
|
|
64
74
|
postman_constructor = default_postman_constructor
|
|
75
|
+
# 网页正则表达式解析失败时,执行抛出异常的函数,可以替换掉用于debug
|
|
76
|
+
raise_regex_error_executor = default_raise_regex_error
|
|
77
|
+
|
|
65
78
|
# debug开关标记
|
|
66
79
|
enable_jm_debug = True
|
|
67
80
|
|
|
@@ -97,6 +110,14 @@ class JmModuleConfig:
|
|
|
97
110
|
from .jm_entity import JmPhotoDetail
|
|
98
111
|
return JmPhotoDetail
|
|
99
112
|
|
|
113
|
+
@classmethod
|
|
114
|
+
def image_class(cls):
|
|
115
|
+
if cls.CLASS_IMAGE is not None:
|
|
116
|
+
return cls.CLASS_IMAGE
|
|
117
|
+
|
|
118
|
+
from .jm_entity import JmImageDetail
|
|
119
|
+
return JmImageDetail
|
|
120
|
+
|
|
100
121
|
@classmethod
|
|
101
122
|
def client_impl_class(cls, client_key: str):
|
|
102
123
|
client_impl_dict = cls.CLASS_CLIENT_IMPL
|
|
@@ -107,6 +128,13 @@ class JmModuleConfig:
|
|
|
107
128
|
|
|
108
129
|
return impl_class
|
|
109
130
|
|
|
131
|
+
@classmethod
|
|
132
|
+
def exception(cls, msg: str):
|
|
133
|
+
if cls.CLASS_EXCEPTION is not None:
|
|
134
|
+
return cls.CLASS_EXCEPTION(msg)
|
|
135
|
+
|
|
136
|
+
return JmcomicException(msg)
|
|
137
|
+
|
|
110
138
|
@classmethod
|
|
111
139
|
@field_cache("DOMAIN")
|
|
112
140
|
def domain(cls, postman=None):
|
|
@@ -163,7 +191,7 @@ class JmModuleConfig:
|
|
|
163
191
|
postman = postman or cls.new_postman(session=True)
|
|
164
192
|
|
|
165
193
|
url = postman.with_redirect_catching().get(cls.JM_REDIRECT_URL)
|
|
166
|
-
cls.jm_debug('
|
|
194
|
+
cls.jm_debug('获取禁漫URL', f'[{cls.JM_REDIRECT_URL}] → [{url}]')
|
|
167
195
|
return url
|
|
168
196
|
|
|
169
197
|
@classmethod
|
|
@@ -178,10 +206,13 @@ class JmModuleConfig:
|
|
|
178
206
|
|
|
179
207
|
resp = postman.get(cls.JM_PUB_URL)
|
|
180
208
|
if resp.status_code != 200:
|
|
181
|
-
raise
|
|
209
|
+
raise JmModuleConfig.exception(resp.text)
|
|
182
210
|
|
|
183
211
|
from .jm_toolkit import JmcomicText
|
|
184
|
-
|
|
212
|
+
domain_list = JmcomicText.analyse_jm_pub_html(resp.text)
|
|
213
|
+
|
|
214
|
+
cls.jm_debug('获取禁漫全部域名', f'[{resp.url}] → {domain_list}')
|
|
215
|
+
return domain_list
|
|
185
216
|
|
|
186
217
|
album_comment_headers = {
|
|
187
218
|
'authority': '18comic.vip',
|
jmcomic/jm_entity.py
CHANGED
|
@@ -241,11 +241,11 @@ class JmPhotoDetail(DetailEntity):
|
|
|
241
241
|
# 校验参数
|
|
242
242
|
length = len(self.page_arr)
|
|
243
243
|
if index >= length:
|
|
244
|
-
raise
|
|
244
|
+
raise JmModuleConfig.exception(f'创建JmImageDetail失败,{index} >= {length}')
|
|
245
245
|
|
|
246
246
|
data_original = self.get_img_data_original(self.page_arr[index])
|
|
247
247
|
|
|
248
|
-
return
|
|
248
|
+
return JmModuleConfig.image_class().of(
|
|
249
249
|
self.photo_id,
|
|
250
250
|
self.scramble_id,
|
|
251
251
|
data_original,
|
|
@@ -262,7 +262,7 @@ class JmPhotoDetail(DetailEntity):
|
|
|
262
262
|
"""
|
|
263
263
|
data_original_domain = self.data_original_domain
|
|
264
264
|
if data_original_domain is None:
|
|
265
|
-
raise
|
|
265
|
+
raise JmModuleConfig.exception(f'图片域名为空: {self.__dict__}')
|
|
266
266
|
|
|
267
267
|
return f'https://{data_original_domain}/media/photos/{self.photo_id}/{img_name}'
|
|
268
268
|
|
|
@@ -330,13 +330,13 @@ class JmAlbumDetail(DetailEntity):
|
|
|
330
330
|
length = len(self.episode_list)
|
|
331
331
|
|
|
332
332
|
if index >= length:
|
|
333
|
-
raise
|
|
333
|
+
raise JmModuleConfig.exception(f'创建JmPhotoDetail失败,{index} >= {length}')
|
|
334
334
|
|
|
335
335
|
# episode_info: ('212214', '81', '94 突然打來', '2020-08-29')
|
|
336
336
|
episode_info: tuple = self.episode_list[index]
|
|
337
337
|
photo_id, photo_index, photo_title, photo_pub_date = episode_info
|
|
338
338
|
|
|
339
|
-
photo =
|
|
339
|
+
photo = JmModuleConfig.photo_class()(
|
|
340
340
|
photo_id=photo_id,
|
|
341
341
|
scramble_id=self.scramble_id,
|
|
342
342
|
title=photo_title,
|
jmcomic/jm_option.py
CHANGED
|
@@ -10,7 +10,8 @@ class DirRule:
|
|
|
10
10
|
# 根目录 / Photo-序号&标题 /
|
|
11
11
|
'Bd_Pindextitle',
|
|
12
12
|
# 根目录 / Photo-自定义类属性 /
|
|
13
|
-
'Bd_Aauthor_Atitle_Pcustomfield',
|
|
13
|
+
'Bd_Aauthor_Atitle_Pcustomfield',
|
|
14
|
+
# 需要替换JmModuleConfig.CLASS_ALBUM / CLASS_PHOTO才能让自定义属性生效
|
|
14
15
|
]
|
|
15
16
|
|
|
16
17
|
RuleFunc = Callable[[Union[JmAlbumDetail, JmPhotoDetail, None]], str]
|
|
@@ -45,8 +46,10 @@ class DirRule:
|
|
|
45
46
|
path_ls.append(str(ret))
|
|
46
47
|
except BaseException as e:
|
|
47
48
|
# noinspection PyUnboundLocalVariable
|
|
48
|
-
raise
|
|
49
|
-
|
|
49
|
+
raise JmModuleConfig.exception(
|
|
50
|
+
f'路径规则"{self.rule_dsl}"的第{i + 1}个解析出错: {e},'
|
|
51
|
+
f'param is {param}'
|
|
52
|
+
)
|
|
50
53
|
|
|
51
54
|
return fix_filepath('/'.join(path_ls), is_dir=True)
|
|
52
55
|
|
|
@@ -214,7 +217,7 @@ class JmOption:
|
|
|
214
217
|
filepath = self.filepath
|
|
215
218
|
|
|
216
219
|
if filepath is None:
|
|
217
|
-
raise
|
|
220
|
+
raise JmModuleConfig.exception("未指定JmOption的保存路径")
|
|
218
221
|
|
|
219
222
|
PackerUtil.pack(self.deconstruct(), filepath)
|
|
220
223
|
|
jmcomic/jm_toolkit.py
CHANGED
|
@@ -52,7 +52,7 @@ class JmcomicText:
|
|
|
52
52
|
return str(text)
|
|
53
53
|
|
|
54
54
|
if not isinstance(text, str):
|
|
55
|
-
raise
|
|
55
|
+
raise JmModuleConfig.exception(f"无法解析jm车号, 参数类型为: {type(text)}")
|
|
56
56
|
|
|
57
57
|
# 43210
|
|
58
58
|
if text.isdigit():
|
|
@@ -60,7 +60,7 @@ class JmcomicText:
|
|
|
60
60
|
|
|
61
61
|
# Jm43210
|
|
62
62
|
if len(text) <= 2:
|
|
63
|
-
raise
|
|
63
|
+
raise JmModuleConfig.exception(f"无法解析jm车号, 文本为: {text}")
|
|
64
64
|
|
|
65
65
|
# text: JM12341
|
|
66
66
|
c0 = text[0]
|
|
@@ -72,7 +72,7 @@ class JmcomicText:
|
|
|
72
72
|
# https://xxx/photo/412038
|
|
73
73
|
match = cls.pattern_jm_pa_id.search(text)
|
|
74
74
|
if match is None:
|
|
75
|
-
raise
|
|
75
|
+
raise JmModuleConfig.exception(f"无法解析jm车号, 文本为: {text}")
|
|
76
76
|
return match[2]
|
|
77
77
|
|
|
78
78
|
@classmethod
|
|
@@ -141,8 +141,12 @@ class JmcomicText:
|
|
|
141
141
|
field_value = match_field(field_name, pattern_value, html)
|
|
142
142
|
|
|
143
143
|
if field_value is None:
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
JmModuleConfig.raise_regex_error_executor(
|
|
145
|
+
f"文本没有匹配上字段:字段名为'{field_name}',pattern: [{pattern_value.pattern}]",
|
|
146
|
+
html,
|
|
147
|
+
field_name,
|
|
148
|
+
pattern_value
|
|
149
|
+
)
|
|
146
150
|
|
|
147
151
|
# 保存字段
|
|
148
152
|
field_dict[field_name] = field_value
|
|
@@ -167,9 +171,7 @@ class JmcomicText:
|
|
|
167
171
|
|
|
168
172
|
class JmSearchSupport:
|
|
169
173
|
# 用来缩减html的长度
|
|
170
|
-
pattern_html_search_shorten_for = compile('<div class="well well-sm">([\s\S]*)'
|
|
171
|
-
'<div class="row">[\s\S]*'
|
|
172
|
-
'<div class="bot-per visible-xs visible-sm">')
|
|
174
|
+
pattern_html_search_shorten_for = compile('<div class="well well-sm">([\s\S]*)<div class="row">')
|
|
173
175
|
|
|
174
176
|
# 用来提取搜索页面的的album的信息
|
|
175
177
|
pattern_html_search_album_info_list = compile(
|
|
@@ -185,9 +187,24 @@ class JmSearchSupport:
|
|
|
185
187
|
# 用来查找tag列表
|
|
186
188
|
pattern_html_search_tag_list = compile('<a href=".*?">(.*?)</a>')
|
|
187
189
|
|
|
190
|
+
# 查找错误,例如 [错误,關鍵字過短,請至少輸入兩個字以上。]
|
|
191
|
+
pattern_html_search_error = compile('<fieldset>\n<legend>(.*?)</legend>\n<div class=.*?>\n(.*?)\n</div>\n</fieldset>')
|
|
192
|
+
|
|
188
193
|
@classmethod
|
|
189
194
|
def analyse_jm_search_html(cls, html: str) -> JmSearchPage:
|
|
190
|
-
|
|
195
|
+
# 检查是否失败
|
|
196
|
+
match = cls.pattern_html_search_error.search(html)
|
|
197
|
+
if match is not None:
|
|
198
|
+
topic, reason = match[1], match[2]
|
|
199
|
+
JmModuleConfig.raise_regex_error_executor(f'{topic}: {reason}', html)
|
|
200
|
+
|
|
201
|
+
# 缩小文本范围
|
|
202
|
+
match = cls.pattern_html_search_shorten_for.search(html)
|
|
203
|
+
if match is None:
|
|
204
|
+
JmModuleConfig.raise_regex_error_executor('未匹配到搜索结果', html)
|
|
205
|
+
html = match[0]
|
|
206
|
+
|
|
207
|
+
# 提取结果
|
|
191
208
|
album_info_list = cls.pattern_html_search_album_info_list.findall(html)
|
|
192
209
|
|
|
193
210
|
for i, (album_id, title, *args) in enumerate(album_info_list):
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
jmcomic/__init__.py,sha256=P841NJsb9rk_BcH56LkydBcqTWqLJ_2U5Ruo5tCqd2s,176
|
|
2
|
+
jmcomic/api.py,sha256=s1LTgpKQh5hMnl3Im6qD5nvrnusf6NHawzvJKbZxwCo,1864
|
|
3
|
+
jmcomic/jm_client_impl.py,sha256=CxuJEQnF9b_kfAkHVJZByn6JdxOP-noiflm67sjwCtw,14101
|
|
4
|
+
jmcomic/jm_client_interface.py,sha256=OhS-pC2FXQT4vuu2WejypEGns2fbL0yD8ZEItAvSLE8,8073
|
|
5
|
+
jmcomic/jm_config.py,sha256=g2BXvXpYIEHewaMmh4WeHc8jz3kCJFOijls2bfpgdrA,8086
|
|
6
|
+
jmcomic/jm_downloader.py,sha256=NrDp8q7l1-FChAsEUOnWp9Vcx-C3xn5R2Cq6kG4s2nc,5910
|
|
7
|
+
jmcomic/jm_entity.py,sha256=VEw4vCpsmzCJqlOuzLz7O9aeHIuGpwCLX10yzoX4ZIc,12908
|
|
8
|
+
jmcomic/jm_option.py,sha256=X5fOCFpk4h7wQi5pPBJUzhsEMOKgsIRiZH4cNb7gCR8,9494
|
|
9
|
+
jmcomic/jm_toolkit.py,sha256=p0Z6WNAwil-F9S3BRYRnPA-b8uR9a6TA9yhMWATv2KY,12053
|
|
10
|
+
jmcomic-2.1.17.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
11
|
+
jmcomic-2.1.17.dist-info/METADATA,sha256=y2hfchFCFgIU2DzvNYd_sWUwRLgUikGbKfSkDSrX5rc,3922
|
|
12
|
+
jmcomic-2.1.17.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
13
|
+
jmcomic-2.1.17.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
14
|
+
jmcomic-2.1.17.dist-info/RECORD,,
|
jmcomic-2.1.15.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
jmcomic/__init__.py,sha256=GlziFJIG_aXTQ9qAJ-TZ4pwGmNafxiuBJi4BenPQv64,176
|
|
2
|
-
jmcomic/api.py,sha256=s1LTgpKQh5hMnl3Im6qD5nvrnusf6NHawzvJKbZxwCo,1864
|
|
3
|
-
jmcomic/jm_client_impl.py,sha256=Xaaeh14FtbHIutjh6m2jJT_k7lThCefs4CfQ-YOukzg,14014
|
|
4
|
-
jmcomic/jm_client_interface.py,sha256=5cbxTVxkEsTU7O11FN2J34P67_eRbfiFqSKl8wZLim8,8048
|
|
5
|
-
jmcomic/jm_config.py,sha256=p1PU-5SgVvssxCqIqIaN2A3mcMQDk2-bhoCQ5Cj_Ung,7234
|
|
6
|
-
jmcomic/jm_downloader.py,sha256=NrDp8q7l1-FChAsEUOnWp9Vcx-C3xn5R2Cq6kG4s2nc,5910
|
|
7
|
-
jmcomic/jm_entity.py,sha256=Xh7Yl-jOro2oUtkrAcbb6S00MCttveZXhn4ZUs-nDKU,12848
|
|
8
|
-
jmcomic/jm_option.py,sha256=1U3_Yubl7uRF31e6HAKXpzg2apCUS2tk2Wm3w7s2pHM,9442
|
|
9
|
-
jmcomic/jm_toolkit.py,sha256=5B040C6_dDhaBy5VFqW7sdLokYVfxHiu3hNSDYD7vSw,11423
|
|
10
|
-
jmcomic-2.1.15.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
11
|
-
jmcomic-2.1.15.dist-info/METADATA,sha256=Yqg2VUC7zx4t7XvRfBSkyZlz3O8YQnPC9H8Ryv0jR88,3922
|
|
12
|
-
jmcomic-2.1.15.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
13
|
-
jmcomic-2.1.15.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
14
|
-
jmcomic-2.1.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|