jmcomic 2.5.8__tar.gz → 2.5.9__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.
- {jmcomic-2.5.8/src/jmcomic.egg-info → jmcomic-2.5.9}/PKG-INFO +2 -2
- {jmcomic-2.5.8 → jmcomic-2.5.9}/setup.py +1 -1
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/__init__.py +1 -1
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_client_impl.py +4 -4
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_config.py +17 -13
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_downloader.py +10 -3
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_entity.py +16 -9
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_exception.py +2 -8
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_option.py +10 -2
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_plugin.py +34 -5
- {jmcomic-2.5.8 → jmcomic-2.5.9/src/jmcomic.egg-info}/PKG-INFO +2 -2
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic.egg-info/requires.txt +1 -1
- {jmcomic-2.5.8 → jmcomic-2.5.9}/LICENSE +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/README.md +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/setup.cfg +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/api.py +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/cl.py +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_client_interface.py +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic/jm_toolkit.py +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic.egg-info/SOURCES.txt +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic.egg-info/dependency_links.txt +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic.egg-info/entry_points.txt +0 -0
- {jmcomic-2.5.8 → jmcomic-2.5.9}/src/jmcomic.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jmcomic
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.9
|
|
4
4
|
Summary: Python API For JMComic (禁漫天堂)
|
|
5
5
|
Home-page: https://github.com/hect0x7/JMComic-Crawler-Python
|
|
6
6
|
Author: hect0x7
|
|
@@ -20,8 +20,8 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
20
20
|
Requires-Python: >=3.7
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: commonX>=0.6.4
|
|
24
23
|
Requires-Dist: curl_cffi
|
|
24
|
+
Requires-Dist: commonX
|
|
25
25
|
Requires-Dist: PyYAML
|
|
26
26
|
Requires-Dist: Pillow
|
|
27
27
|
Requires-Dist: pycryptodome
|
|
@@ -224,7 +224,7 @@ class AbstractJmClient(
|
|
|
224
224
|
|
|
225
225
|
# noinspection PyMethodMayBeStatic
|
|
226
226
|
def decode(self, url: str):
|
|
227
|
-
if not JmModuleConfig.
|
|
227
|
+
if not JmModuleConfig.FLAG_DECODE_URL_WHEN_LOGGING or '/search/' not in url:
|
|
228
228
|
return url
|
|
229
229
|
|
|
230
230
|
from urllib.parse import unquote
|
|
@@ -767,7 +767,7 @@ class JmApiClient(AbstractJmClient):
|
|
|
767
767
|
# 检查禁漫最新的版本号
|
|
768
768
|
setting_ver = str(resp.model_data.version)
|
|
769
769
|
# 禁漫接口的版本 > jmcomic库内置版本
|
|
770
|
-
if setting_ver > JmMagicConstants.APP_VERSION and JmModuleConfig.
|
|
770
|
+
if setting_ver > JmMagicConstants.APP_VERSION and JmModuleConfig.FLAG_USE_VERSION_NEWER_IF_BEHIND:
|
|
771
771
|
jm_log('api.setting', f'change APP_VERSION from [{JmMagicConstants.APP_VERSION}] to [{setting_ver}]')
|
|
772
772
|
JmMagicConstants.APP_VERSION = setting_ver
|
|
773
773
|
|
|
@@ -883,7 +883,7 @@ class JmApiClient(AbstractJmClient):
|
|
|
883
883
|
ts = time_stamp()
|
|
884
884
|
token, tokenparam = JmCryptoTool.token_and_tokenparam(ts, secret=JmMagicConstants.APP_TOKEN_SECRET_2)
|
|
885
885
|
|
|
886
|
-
elif JmModuleConfig.
|
|
886
|
+
elif JmModuleConfig.FLAG_USE_FIX_TIMESTAMP:
|
|
887
887
|
ts, token, tokenparam = JmModuleConfig.get_fix_ts_token_tokenparam()
|
|
888
888
|
|
|
889
889
|
else:
|
|
@@ -954,7 +954,7 @@ class JmApiClient(AbstractJmClient):
|
|
|
954
954
|
|
|
955
955
|
def after_init(self):
|
|
956
956
|
# 保证拥有cookies,因为移动端要求必须携带cookies,否则会直接跳转同一本子【禁漫娘】
|
|
957
|
-
if JmModuleConfig.
|
|
957
|
+
if JmModuleConfig.FLAG_API_CLIENT_REQUIRE_COOKIES:
|
|
958
958
|
self.ensure_have_cookies()
|
|
959
959
|
|
|
960
960
|
client_init_cookies_lock = Lock()
|
|
@@ -146,18 +146,18 @@ class JmModuleConfig:
|
|
|
146
146
|
REGISTRY_EXCEPTION_LISTENER = {}
|
|
147
147
|
|
|
148
148
|
# 执行log的函数
|
|
149
|
-
|
|
149
|
+
EXECUTOR_LOG = default_jm_logging
|
|
150
150
|
|
|
151
151
|
# 使用固定时间戳
|
|
152
|
-
|
|
152
|
+
FLAG_USE_FIX_TIMESTAMP = True
|
|
153
153
|
# 移动端Client初始化cookies
|
|
154
|
-
|
|
154
|
+
FLAG_API_CLIENT_REQUIRE_COOKIES = True
|
|
155
155
|
# log开关标记
|
|
156
|
-
|
|
156
|
+
FLAG_ENABLE_JM_LOG = True
|
|
157
157
|
# log时解码url
|
|
158
|
-
|
|
158
|
+
FLAG_DECODE_URL_WHEN_LOGGING = True
|
|
159
159
|
# 当内置的版本号落后时,使用最新的禁漫app版本号
|
|
160
|
-
|
|
160
|
+
FLAG_USE_VERSION_NEWER_IF_BEHIND = True
|
|
161
161
|
|
|
162
162
|
# 关联dir_rule的自定义字段与对应的处理函数
|
|
163
163
|
# 例如:
|
|
@@ -165,6 +165,10 @@ class JmModuleConfig:
|
|
|
165
165
|
AFIELD_ADVICE = dict()
|
|
166
166
|
PFIELD_ADVICE = dict()
|
|
167
167
|
|
|
168
|
+
# 当发生 oserror: [Errno 36] File name too long 时,
|
|
169
|
+
# 把文件名限制在指定个字符以内
|
|
170
|
+
VAR_FILE_NAME_LENGTH_LIMIT = 100
|
|
171
|
+
|
|
168
172
|
@classmethod
|
|
169
173
|
def downloader_class(cls):
|
|
170
174
|
if cls.CLASS_DOWNLOADER is not None:
|
|
@@ -319,12 +323,12 @@ class JmModuleConfig:
|
|
|
319
323
|
# noinspection PyUnusedLocal
|
|
320
324
|
@classmethod
|
|
321
325
|
def jm_log(cls, topic: str, msg: str):
|
|
322
|
-
if cls.
|
|
323
|
-
cls.
|
|
326
|
+
if cls.FLAG_ENABLE_JM_LOG is True:
|
|
327
|
+
cls.EXECUTOR_LOG(topic, msg)
|
|
324
328
|
|
|
325
329
|
@classmethod
|
|
326
330
|
def disable_jm_log(cls):
|
|
327
|
-
cls.
|
|
331
|
+
cls.FLAG_ENABLE_JM_LOG = False
|
|
328
332
|
|
|
329
333
|
@classmethod
|
|
330
334
|
def new_postman(cls, session=False, **kwargs):
|
|
@@ -347,7 +351,7 @@ class JmModuleConfig:
|
|
|
347
351
|
DEFAULT_CLIENT_CACHE = None # 默认关闭Client缓存。缓存的配置详见 CacheRegistry
|
|
348
352
|
DEFAULT_PROXIES = ProxyBuilder.system_proxy() # 默认使用系统代理
|
|
349
353
|
|
|
350
|
-
|
|
354
|
+
DEFAULT_OPTION_DICT: dict = {
|
|
351
355
|
'log': None,
|
|
352
356
|
'dir_rule': {'rule': 'Bd_Pname', 'base_dir': None},
|
|
353
357
|
'download': {
|
|
@@ -364,7 +368,7 @@ class JmModuleConfig:
|
|
|
364
368
|
'postman': {
|
|
365
369
|
'type': 'cffi',
|
|
366
370
|
'meta_data': {
|
|
367
|
-
'impersonate': '
|
|
371
|
+
'impersonate': 'chrome',
|
|
368
372
|
'headers': None,
|
|
369
373
|
'proxies': None,
|
|
370
374
|
}
|
|
@@ -387,11 +391,11 @@ class JmModuleConfig:
|
|
|
387
391
|
"""
|
|
388
392
|
from copy import deepcopy
|
|
389
393
|
|
|
390
|
-
option_dict = deepcopy(cls.
|
|
394
|
+
option_dict = deepcopy(cls.DEFAULT_OPTION_DICT)
|
|
391
395
|
|
|
392
396
|
# log
|
|
393
397
|
if option_dict['log'] is None:
|
|
394
|
-
option_dict['log'] = cls.
|
|
398
|
+
option_dict['log'] = cls.FLAG_ENABLE_JM_LOG
|
|
395
399
|
|
|
396
400
|
# dir_rule.base_dir
|
|
397
401
|
dir_rule = option_dict['dir_rule']
|
|
@@ -29,7 +29,7 @@ class DownloadCallback:
|
|
|
29
29
|
f'章节下载完成: [{photo.id}] ({photo.album_id}[{photo.index}/{len(photo.from_album)}])')
|
|
30
30
|
|
|
31
31
|
def before_image(self, image: JmImageDetail, img_save_path):
|
|
32
|
-
if image.
|
|
32
|
+
if image.exists:
|
|
33
33
|
jm_log('image.before',
|
|
34
34
|
f'图片已存在: {image.tag} ← [{img_save_path}]'
|
|
35
35
|
)
|
|
@@ -63,6 +63,8 @@ class JmDownloader(DownloadCallback):
|
|
|
63
63
|
|
|
64
64
|
def download_by_album_detail(self, album: JmAlbumDetail, client: JmcomicClient):
|
|
65
65
|
self.before_album(album)
|
|
66
|
+
if album.skip:
|
|
67
|
+
return
|
|
66
68
|
self.execute_by_condition(
|
|
67
69
|
iter_objs=album,
|
|
68
70
|
apply=lambda photo: self.download_by_photo_detail(photo, client),
|
|
@@ -80,6 +82,8 @@ class JmDownloader(DownloadCallback):
|
|
|
80
82
|
client.check_photo(photo)
|
|
81
83
|
|
|
82
84
|
self.before_photo(photo)
|
|
85
|
+
if photo.skip:
|
|
86
|
+
return
|
|
83
87
|
self.execute_by_condition(
|
|
84
88
|
iter_objs=photo,
|
|
85
89
|
apply=lambda image: self.download_by_image_detail(image, client),
|
|
@@ -91,16 +95,19 @@ class JmDownloader(DownloadCallback):
|
|
|
91
95
|
img_save_path = self.option.decide_image_filepath(image)
|
|
92
96
|
|
|
93
97
|
image.save_path = img_save_path
|
|
94
|
-
image.
|
|
98
|
+
image.exists = file_exists(img_save_path)
|
|
95
99
|
|
|
96
100
|
self.before_image(image, img_save_path)
|
|
97
101
|
|
|
102
|
+
if image.skip:
|
|
103
|
+
return
|
|
104
|
+
|
|
98
105
|
# let option decide use_cache and decode_image
|
|
99
106
|
use_cache = self.option.decide_download_cache(image)
|
|
100
107
|
decode_image = self.option.decide_download_image_decode(image)
|
|
101
108
|
|
|
102
109
|
# skip download
|
|
103
|
-
if use_cache is True and image.
|
|
110
|
+
if use_cache is True and image.exists:
|
|
104
111
|
return
|
|
105
112
|
|
|
106
113
|
e = None
|
|
@@ -3,6 +3,14 @@ from common import *
|
|
|
3
3
|
from .jm_config import *
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
class Downloadable:
|
|
7
|
+
|
|
8
|
+
def __init__(self):
|
|
9
|
+
self.save_path: str = ''
|
|
10
|
+
self.exists: bool = False
|
|
11
|
+
self.skip = False
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
class JmBaseEntity:
|
|
7
15
|
|
|
8
16
|
def to_file(self, filepath):
|
|
@@ -117,7 +125,7 @@ class DetailEntity(JmBaseEntity, IndexedEntity):
|
|
|
117
125
|
def __str__(self):
|
|
118
126
|
return f'{self.__class__.__name__}' \
|
|
119
127
|
'{' \
|
|
120
|
-
f'{self.id}: {self.title}'\
|
|
128
|
+
f'{self.id}: {self.title}' \
|
|
121
129
|
'}'
|
|
122
130
|
|
|
123
131
|
@classmethod
|
|
@@ -156,7 +164,7 @@ class DetailEntity(JmBaseEntity, IndexedEntity):
|
|
|
156
164
|
return getattr(detail, ref)
|
|
157
165
|
|
|
158
166
|
|
|
159
|
-
class JmImageDetail(JmBaseEntity):
|
|
167
|
+
class JmImageDetail(JmBaseEntity, Downloadable):
|
|
160
168
|
|
|
161
169
|
def __init__(self,
|
|
162
170
|
aid,
|
|
@@ -167,7 +175,8 @@ class JmImageDetail(JmBaseEntity):
|
|
|
167
175
|
from_photo=None,
|
|
168
176
|
query_params=None,
|
|
169
177
|
index=-1,
|
|
170
|
-
)
|
|
178
|
+
):
|
|
179
|
+
super().__init__()
|
|
171
180
|
if scramble_id is None or (isinstance(scramble_id, str) and scramble_id == ''):
|
|
172
181
|
from .jm_toolkit import ExceptionTool
|
|
173
182
|
ExceptionTool.raises(f'图片的scramble_id不能为空')
|
|
@@ -182,10 +191,6 @@ class JmImageDetail(JmBaseEntity):
|
|
|
182
191
|
self.query_params: Optional[str] = query_params
|
|
183
192
|
self.index = index # 从1开始
|
|
184
193
|
|
|
185
|
-
# temp fields, in order to simplify passing parameter
|
|
186
|
-
self.save_path: str = ''
|
|
187
|
-
self.is_exists: bool = False
|
|
188
|
-
|
|
189
194
|
@property
|
|
190
195
|
def filename_without_suffix(self):
|
|
191
196
|
return self.img_file_name
|
|
@@ -252,7 +257,7 @@ class JmImageDetail(JmBaseEntity):
|
|
|
252
257
|
return True
|
|
253
258
|
|
|
254
259
|
|
|
255
|
-
class JmPhotoDetail(DetailEntity):
|
|
260
|
+
class JmPhotoDetail(DetailEntity, Downloadable):
|
|
256
261
|
|
|
257
262
|
def __init__(self,
|
|
258
263
|
photo_id,
|
|
@@ -267,6 +272,7 @@ class JmPhotoDetail(DetailEntity):
|
|
|
267
272
|
author=None,
|
|
268
273
|
from_album=None,
|
|
269
274
|
):
|
|
275
|
+
super().__init__()
|
|
270
276
|
self.photo_id: str = str(photo_id)
|
|
271
277
|
self.scramble_id: str = str(scramble_id)
|
|
272
278
|
self.name: str = str(name).strip()
|
|
@@ -411,7 +417,7 @@ class JmPhotoDetail(DetailEntity):
|
|
|
411
417
|
return True
|
|
412
418
|
|
|
413
419
|
|
|
414
|
-
class JmAlbumDetail(DetailEntity):
|
|
420
|
+
class JmAlbumDetail(DetailEntity, Downloadable):
|
|
415
421
|
|
|
416
422
|
def __init__(self,
|
|
417
423
|
album_id,
|
|
@@ -430,6 +436,7 @@ class JmAlbumDetail(DetailEntity):
|
|
|
430
436
|
tags,
|
|
431
437
|
related_list=None,
|
|
432
438
|
):
|
|
439
|
+
super().__init__()
|
|
433
440
|
self.album_id: str = str(album_id)
|
|
434
441
|
self.scramble_id: str = str(scramble_id)
|
|
435
442
|
self.name: str = name
|
|
@@ -72,13 +72,6 @@ class ExceptionTool:
|
|
|
72
72
|
CONTEXT_KEY_RE_PATTERN = 'pattern'
|
|
73
73
|
CONTEXT_KEY_MISSING_JM_ID = 'missing_jm_id'
|
|
74
74
|
|
|
75
|
-
# 兼容旧版本
|
|
76
|
-
|
|
77
|
-
EXTRA_KEY_RESP = 'resp'
|
|
78
|
-
EXTRA_KEY_HTML = 'html'
|
|
79
|
-
EXTRA_KEY_RE_PATTERN = 'pattern'
|
|
80
|
-
EXTRA_KEY_MISSING_JM_ID = 'missing_jm_id'
|
|
81
|
-
|
|
82
75
|
@classmethod
|
|
83
76
|
def raises(cls,
|
|
84
77
|
msg: str,
|
|
@@ -144,7 +137,8 @@ class ExceptionTool:
|
|
|
144
137
|
:param resp: 响应对象
|
|
145
138
|
:param jmid: 禁漫本子/章节id
|
|
146
139
|
"""
|
|
147
|
-
|
|
140
|
+
from .jm_toolkit import JmcomicText
|
|
141
|
+
url = JmcomicText.format_album_url(jmid)
|
|
148
142
|
|
|
149
143
|
req_type = "本子" if "album" in url else "章节"
|
|
150
144
|
cls.raises(
|
|
@@ -285,7 +285,15 @@ class JmOption:
|
|
|
285
285
|
)
|
|
286
286
|
|
|
287
287
|
if ensure_exists:
|
|
288
|
-
|
|
288
|
+
try:
|
|
289
|
+
mkdir_if_not_exists(save_dir)
|
|
290
|
+
except OSError as e:
|
|
291
|
+
if e.errno == 36:
|
|
292
|
+
# 目录名过长
|
|
293
|
+
limit = JmModuleConfig.VAR_FILE_NAME_LENGTH_LIMIT
|
|
294
|
+
jm_log('error', f'目录名过长,无法创建目录,强制缩短到{limit}个字符并重试')
|
|
295
|
+
save_dir = save_dir[0:limit]
|
|
296
|
+
mkdir_if_not_exists(save_dir)
|
|
289
297
|
|
|
290
298
|
return save_dir
|
|
291
299
|
|
|
@@ -359,7 +367,7 @@ class JmOption:
|
|
|
359
367
|
def deconstruct(self) -> Dict:
|
|
360
368
|
return {
|
|
361
369
|
'version': JmModuleConfig.JM_OPTION_VER,
|
|
362
|
-
'log': JmModuleConfig.
|
|
370
|
+
'log': JmModuleConfig.FLAG_ENABLE_JM_LOG,
|
|
363
371
|
'dir_rule': {
|
|
364
372
|
'rule': self.dir_rule.rule_dsl,
|
|
365
373
|
'base_dir': self.dir_rule.base_dir,
|
|
@@ -445,9 +445,7 @@ class ImageSuffixFilterPlugin(JmOptionPlugin):
|
|
|
445
445
|
if image.img_file_suffix not in allowed_suffix_set:
|
|
446
446
|
self.log(f'跳过下载图片: {image.tag},'
|
|
447
447
|
f'因为其后缀\'{image.img_file_suffix}\'不在允许的后缀集合{allowed_suffix_set}内')
|
|
448
|
-
|
|
449
|
-
image.is_exists = True
|
|
450
|
-
return True
|
|
448
|
+
image.skip = True
|
|
451
449
|
|
|
452
450
|
# let option decide
|
|
453
451
|
return option_decide_cache(image)
|
|
@@ -484,7 +482,7 @@ class LogTopicFilterPlugin(JmOptionPlugin):
|
|
|
484
482
|
if whitelist is not None:
|
|
485
483
|
whitelist = set(whitelist)
|
|
486
484
|
|
|
487
|
-
old_jm_log = JmModuleConfig.
|
|
485
|
+
old_jm_log = JmModuleConfig.EXECUTOR_LOG
|
|
488
486
|
|
|
489
487
|
def new_jm_log(topic, msg):
|
|
490
488
|
if whitelist is not None and topic not in whitelist:
|
|
@@ -492,7 +490,7 @@ class LogTopicFilterPlugin(JmOptionPlugin):
|
|
|
492
490
|
|
|
493
491
|
old_jm_log(topic, msg)
|
|
494
492
|
|
|
495
|
-
JmModuleConfig.
|
|
493
|
+
JmModuleConfig.EXECUTOR_LOG = new_jm_log
|
|
496
494
|
|
|
497
495
|
|
|
498
496
|
class AutoSetBrowserCookiesPlugin(JmOptionPlugin):
|
|
@@ -963,3 +961,34 @@ class SubscribeAlbumUpdatePlugin(JmOptionPlugin):
|
|
|
963
961
|
is_new_photo = True
|
|
964
962
|
|
|
965
963
|
return len(photo_new_list) != 0, photo_new_list
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
class SkipPhotoWithFewImagesPlugin(JmOptionPlugin):
|
|
967
|
+
plugin_key = 'skip_photo_with_few_images'
|
|
968
|
+
|
|
969
|
+
def invoke(self,
|
|
970
|
+
at_least_image_count: int,
|
|
971
|
+
photo: Optional[JmPhotoDetail] = None,
|
|
972
|
+
image: Optional[JmImageDetail] = None,
|
|
973
|
+
album: Optional[JmAlbumDetail] = None,
|
|
974
|
+
**kwargs
|
|
975
|
+
):
|
|
976
|
+
self.try_mark_photo_skip_and_log(photo, at_least_image_count)
|
|
977
|
+
if image is not None:
|
|
978
|
+
self.try_mark_photo_skip_and_log(image.from_photo, at_least_image_count)
|
|
979
|
+
|
|
980
|
+
def try_mark_photo_skip_and_log(self, photo: JmPhotoDetail, at_least_image_count: int):
|
|
981
|
+
if photo is None:
|
|
982
|
+
return
|
|
983
|
+
|
|
984
|
+
if len(photo) >= at_least_image_count:
|
|
985
|
+
return
|
|
986
|
+
|
|
987
|
+
self.log(f'跳过下载章节: {photo.id} ({photo.album_id}[{photo.index}/{len(photo.from_album)}]),'
|
|
988
|
+
f'因为其图片数: {len(photo)} < {at_least_image_count} (at_least_image_count)')
|
|
989
|
+
photo.skip = True
|
|
990
|
+
|
|
991
|
+
@classmethod
|
|
992
|
+
@field_cache() # 单例
|
|
993
|
+
def build(cls, option: JmOption) -> 'JmOptionPlugin':
|
|
994
|
+
return super().build(option)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jmcomic
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.9
|
|
4
4
|
Summary: Python API For JMComic (禁漫天堂)
|
|
5
5
|
Home-page: https://github.com/hect0x7/JMComic-Crawler-Python
|
|
6
6
|
Author: hect0x7
|
|
@@ -20,8 +20,8 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
20
20
|
Requires-Python: >=3.7
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: commonX>=0.6.4
|
|
24
23
|
Requires-Dist: curl_cffi
|
|
24
|
+
Requires-Dist: commonX
|
|
25
25
|
Requires-Dist: PyYAML
|
|
26
26
|
Requires-Dist: Pillow
|
|
27
27
|
Requires-Dist: pycryptodome
|
|
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
|