jmcomic 2.6.4__tar.gz → 2.6.6__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.6.4/src/jmcomic.egg-info → jmcomic-2.6.6}/PKG-INFO +1 -1
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/__init__.py +1 -1
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_client_impl.py +69 -59
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_config.py +9 -7
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_plugin.py +25 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6/src/jmcomic.egg-info}/PKG-INFO +1 -1
- {jmcomic-2.6.4 → jmcomic-2.6.6}/LICENSE +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/README.md +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/pyproject.toml +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/setup.cfg +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/setup.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/api.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/cl.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_client_interface.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_downloader.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_entity.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_exception.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_option.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic/jm_toolkit.py +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic.egg-info/SOURCES.txt +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic.egg-info/dependency_links.txt +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic.egg-info/entry_points.txt +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic.egg-info/requires.txt +0 -0
- {jmcomic-2.6.4 → jmcomic-2.6.6}/src/jmcomic.egg-info/top_level.txt +0 -0
|
@@ -26,6 +26,7 @@ class AbstractJmClient(
|
|
|
26
26
|
super().__init__(postman)
|
|
27
27
|
self.retry_times = retry_times
|
|
28
28
|
self.domain_list = domain_list
|
|
29
|
+
self.domain_retry_strategy = None
|
|
29
30
|
self.CLIENT_CACHE = None
|
|
30
31
|
self._username = None # help for favorite_folder method
|
|
31
32
|
self.enable_cache()
|
|
@@ -44,23 +45,14 @@ class AbstractJmClient(
|
|
|
44
45
|
return JmcomicText.format_url(api_path, domain)
|
|
45
46
|
|
|
46
47
|
def get_jm_image(self, img_url) -> JmImageResp:
|
|
47
|
-
|
|
48
|
-
def callback(resp):
|
|
49
|
-
"""
|
|
50
|
-
使用此方法包装 self.get,使得图片数据为空时,判定为请求失败时,走重试逻辑
|
|
51
|
-
"""
|
|
52
|
-
resp = JmImageResp(resp)
|
|
53
|
-
resp.require_success()
|
|
54
|
-
return resp
|
|
55
|
-
|
|
56
|
-
return self.get(img_url, callback=callback, headers=JmModuleConfig.new_html_headers())
|
|
48
|
+
return self.get(img_url, is_image=True, headers=JmModuleConfig.new_html_headers())
|
|
57
49
|
|
|
58
50
|
def request_with_retry(self,
|
|
59
51
|
request,
|
|
60
52
|
url,
|
|
61
53
|
domain_index=0,
|
|
62
54
|
retry_count=0,
|
|
63
|
-
|
|
55
|
+
is_image=False,
|
|
64
56
|
**kwargs,
|
|
65
57
|
):
|
|
66
58
|
"""
|
|
@@ -74,11 +66,19 @@ class AbstractJmClient(
|
|
|
74
66
|
:param url: 图片url / path (/album/xxx)
|
|
75
67
|
:param domain_index: 域名下标
|
|
76
68
|
:param retry_count: 重试次数
|
|
77
|
-
:param
|
|
69
|
+
:param is_image: 是否是图片请求
|
|
78
70
|
:param kwargs: 请求方法的kwargs
|
|
79
71
|
"""
|
|
72
|
+
if self.domain_retry_strategy:
|
|
73
|
+
return self.domain_retry_strategy(self,
|
|
74
|
+
request,
|
|
75
|
+
url,
|
|
76
|
+
is_image,
|
|
77
|
+
**kwargs,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
80
|
if domain_index >= len(self.domain_list):
|
|
81
|
-
return self.fallback(request, url, domain_index, retry_count, **kwargs)
|
|
81
|
+
return self.fallback(request, url, domain_index, retry_count, is_image, **kwargs)
|
|
82
82
|
|
|
83
83
|
url_backup = url
|
|
84
84
|
|
|
@@ -87,12 +87,12 @@ class AbstractJmClient(
|
|
|
87
87
|
domain = self.domain_list[domain_index]
|
|
88
88
|
url = self.of_api_url(url, domain)
|
|
89
89
|
|
|
90
|
-
self.update_request_with_specify_domain(kwargs, domain)
|
|
90
|
+
self.update_request_with_specify_domain(kwargs, domain, is_image)
|
|
91
91
|
|
|
92
92
|
jm_log(self.log_topic(), self.decode(url))
|
|
93
|
-
|
|
93
|
+
elif is_image:
|
|
94
94
|
# 图片url
|
|
95
|
-
self.update_request_with_specify_domain(kwargs, None,
|
|
95
|
+
self.update_request_with_specify_domain(kwargs, None, is_image)
|
|
96
96
|
|
|
97
97
|
if domain_index != 0 or retry_count != 0:
|
|
98
98
|
jm_log(f'req.retry',
|
|
@@ -106,14 +106,8 @@ class AbstractJmClient(
|
|
|
106
106
|
|
|
107
107
|
try:
|
|
108
108
|
resp = request(url, **kwargs)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if callback is not None:
|
|
112
|
-
resp = callback(resp)
|
|
113
|
-
|
|
114
|
-
# 依然是回调,在最后返回之前,还可以判断resp是否重试
|
|
115
|
-
resp = self.raise_if_resp_should_retry(resp)
|
|
116
|
-
|
|
109
|
+
# 在最后返回之前,还可以判断resp是否重试
|
|
110
|
+
resp = self.raise_if_resp_should_retry(resp, is_image)
|
|
117
111
|
return resp
|
|
118
112
|
except Exception as e:
|
|
119
113
|
if self.retry_times == 0:
|
|
@@ -122,15 +116,19 @@ class AbstractJmClient(
|
|
|
122
116
|
self.before_retry(e, kwargs, retry_count, url)
|
|
123
117
|
|
|
124
118
|
if retry_count < self.retry_times:
|
|
125
|
-
return self.request_with_retry(request, url_backup, domain_index, retry_count + 1,
|
|
119
|
+
return self.request_with_retry(request, url_backup, domain_index, retry_count + 1, is_image, **kwargs)
|
|
126
120
|
else:
|
|
127
|
-
return self.request_with_retry(request, url_backup, domain_index + 1, 0,
|
|
121
|
+
return self.request_with_retry(request, url_backup, domain_index + 1, 0, is_image, **kwargs)
|
|
128
122
|
|
|
129
123
|
# noinspection PyMethodMayBeStatic
|
|
130
|
-
def raise_if_resp_should_retry(self, resp):
|
|
124
|
+
def raise_if_resp_should_retry(self, resp, is_image):
|
|
131
125
|
"""
|
|
132
126
|
依然是回调,在最后返回之前,还可以判断resp是否重试
|
|
133
127
|
"""
|
|
128
|
+
if is_image is True:
|
|
129
|
+
resp = JmImageResp(resp)
|
|
130
|
+
resp.require_success()
|
|
131
|
+
|
|
134
132
|
return resp
|
|
135
133
|
|
|
136
134
|
def update_request_with_specify_domain(self, kwargs: dict, domain: Optional[str], is_image: bool = False):
|
|
@@ -208,7 +206,7 @@ class AbstractJmClient(
|
|
|
208
206
|
self.domain_list = domain_list
|
|
209
207
|
|
|
210
208
|
# noinspection PyUnusedLocal
|
|
211
|
-
def fallback(self, request, url, domain_index, retry_count, **kwargs):
|
|
209
|
+
def fallback(self, request, url, domain_index, retry_count, is_image, **kwargs):
|
|
212
210
|
msg = f"请求重试全部失败: [{url}], {self.domain_list}"
|
|
213
211
|
jm_log('req.fallback', msg)
|
|
214
212
|
ExceptionTool.raises(msg, {}, RequestRetryAllFailException)
|
|
@@ -965,17 +963,16 @@ class JmApiClient(AbstractJmClient):
|
|
|
965
963
|
# 2. 是否是特殊的内容
|
|
966
964
|
# 暂无
|
|
967
965
|
|
|
968
|
-
def raise_if_resp_should_retry(self, resp):
|
|
966
|
+
def raise_if_resp_should_retry(self, resp, is_image):
|
|
969
967
|
"""
|
|
970
968
|
该方法会判断resp返回值是否是json格式,
|
|
971
969
|
如果不是,大概率是禁漫内部异常,需要进行重试
|
|
972
970
|
|
|
973
971
|
由于完整的json格式校验会有性能开销,所以只做简单的检查,
|
|
974
972
|
只校验第一个有效字符是不是 '{',如果不是,就认为异常数据,需要重试
|
|
975
|
-
|
|
976
|
-
:param resp: 响应对象
|
|
977
|
-
:return: resp
|
|
978
973
|
"""
|
|
974
|
+
resp = super().raise_if_resp_should_retry(resp, is_image)
|
|
975
|
+
|
|
979
976
|
if isinstance(resp, JmResp):
|
|
980
977
|
# 不对包装过的resp对象做校验,包装者自行校验
|
|
981
978
|
# 例如图片请求
|
|
@@ -1015,6 +1012,23 @@ class JmApiClient(AbstractJmClient):
|
|
|
1015
1012
|
|
|
1016
1013
|
client_update_domain_lock = Lock()
|
|
1017
1014
|
|
|
1015
|
+
def req_api_domain_server(self, url):
|
|
1016
|
+
resp = self.postman.get(url)
|
|
1017
|
+
text: str = resp.text
|
|
1018
|
+
# 去掉开头非ascii字符
|
|
1019
|
+
while text and not text[0].isascii():
|
|
1020
|
+
text = text[1:]
|
|
1021
|
+
res_json = JmCryptoTool.decode_resp_data(text, '', JmMagicConstants.API_DOMAIN_SERVER_SECRET)
|
|
1022
|
+
res_data = json_loads(res_json)
|
|
1023
|
+
|
|
1024
|
+
# 检查返回值
|
|
1025
|
+
if not res_data.get('Server', None):
|
|
1026
|
+
jm_log('api.update_domain.empty',
|
|
1027
|
+
f'获取禁漫最新API域名失败, 返回值: {res_json}')
|
|
1028
|
+
return None
|
|
1029
|
+
else:
|
|
1030
|
+
return res_data['Server']
|
|
1031
|
+
|
|
1018
1032
|
def update_api_domain(self):
|
|
1019
1033
|
if True is JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN_DONE:
|
|
1020
1034
|
return
|
|
@@ -1022,33 +1036,29 @@ class JmApiClient(AbstractJmClient):
|
|
|
1022
1036
|
with self.client_update_domain_lock:
|
|
1023
1037
|
if True is JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN_DONE:
|
|
1024
1038
|
return
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
jm_log('api.update_domain.
|
|
1034
|
-
f'
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
f'可通过代码[JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN=False]关闭自动更新API域名. 异常: {e}'
|
|
1049
|
-
)
|
|
1050
|
-
finally:
|
|
1051
|
-
JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN_DONE = True
|
|
1039
|
+
# 遍历多个域名服务器
|
|
1040
|
+
for url in JmModuleConfig.API_URL_DOMAIN_SERVER_LIST:
|
|
1041
|
+
try:
|
|
1042
|
+
# 获取域名列表
|
|
1043
|
+
new_server_list = self.req_api_domain_server(url)
|
|
1044
|
+
if new_server_list is None:
|
|
1045
|
+
continue
|
|
1046
|
+
old_server_list = JmModuleConfig.DOMAIN_API_LIST
|
|
1047
|
+
jm_log('api.update_domain.success',
|
|
1048
|
+
f'获取到最新的API域名,替换jmcomic内置域名:(new){new_server_list} ---→ (old){old_server_list}'
|
|
1049
|
+
)
|
|
1050
|
+
# 更新域名
|
|
1051
|
+
if sorted(self.domain_list) == sorted(old_server_list):
|
|
1052
|
+
self.domain_list = new_server_list
|
|
1053
|
+
JmModuleConfig.DOMAIN_API_LIST = new_server_list
|
|
1054
|
+
break
|
|
1055
|
+
except Exception as e:
|
|
1056
|
+
jm_log('api.update_domain.error',
|
|
1057
|
+
f'通过[{url}]自动更新API域名失败,仍使用jmcomic内置域名。'
|
|
1058
|
+
f'可通过代码[JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN=False]关闭自动更新API域名. 异常: {e}'
|
|
1059
|
+
)
|
|
1060
|
+
# set done finally
|
|
1061
|
+
JmModuleConfig.FLAG_API_CLIENT_AUTO_UPDATE_DOMAIN_DONE = True
|
|
1052
1062
|
|
|
1053
1063
|
client_init_cookies_lock = Lock()
|
|
1054
1064
|
|
|
@@ -77,7 +77,7 @@ class JmMagicConstants:
|
|
|
77
77
|
APP_TOKEN_SECRET_2 = '18comicAPPContent'
|
|
78
78
|
APP_DATA_SECRET = '185Hcomic3PAPP7R'
|
|
79
79
|
API_DOMAIN_SERVER_SECRET = 'diosfjckwpqpdfjkvnqQjsik'
|
|
80
|
-
APP_VERSION = '
|
|
80
|
+
APP_VERSION = '2.0.6'
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
# 模块级别共用配置
|
|
@@ -128,15 +128,17 @@ class JmModuleConfig:
|
|
|
128
128
|
|
|
129
129
|
# 移动端API域名
|
|
130
130
|
DOMAIN_API_LIST = shuffled('''
|
|
131
|
-
www.
|
|
132
|
-
www.
|
|
133
|
-
www.cdnplaystation6.
|
|
134
|
-
www.
|
|
135
|
-
www.cdn-mspjmapiproxy.xyz
|
|
131
|
+
www.cdnaspa.vip
|
|
132
|
+
www.cdnaspa.club
|
|
133
|
+
www.cdnplaystation6.vip
|
|
134
|
+
www.cdnplaystation6.cc
|
|
136
135
|
''')
|
|
137
136
|
|
|
138
137
|
# 获取最新移动端API域名的地址
|
|
139
|
-
|
|
138
|
+
API_URL_DOMAIN_SERVER_LIST = shuffled('''
|
|
139
|
+
https://rup4a04-c01.tos-ap-southeast-1.bytepluses.com/newsvr-2025.txt
|
|
140
|
+
https://rup4a04-c02.tos-cn-hongkong.bytepluses.com/newsvr-2025.txt
|
|
141
|
+
''')
|
|
140
142
|
|
|
141
143
|
APP_HEADERS_TEMPLATE = {
|
|
142
144
|
'Accept-Encoding': 'gzip, deflate',
|
|
@@ -1216,3 +1216,28 @@ class ReplacePathStringPlugin(JmOptionPlugin):
|
|
|
1216
1216
|
return original_path
|
|
1217
1217
|
|
|
1218
1218
|
self.option.decide_image_save_dir = new_decide_dir
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
class AdvancedRetryPlugin(JmOptionPlugin):
|
|
1222
|
+
plugin_key = 'advanced-retry'
|
|
1223
|
+
|
|
1224
|
+
def invoke(self,
|
|
1225
|
+
retry_config,
|
|
1226
|
+
**kwargs):
|
|
1227
|
+
new_jm_client: Callable = self.option.new_jm_client
|
|
1228
|
+
|
|
1229
|
+
def hook_new_jm_client(*args, **kwargs):
|
|
1230
|
+
client: AbstractJmClient = new_jm_client(*args, **kwargs)
|
|
1231
|
+
client.domain_retry_strategy = self.request_with_retry
|
|
1232
|
+
return client
|
|
1233
|
+
|
|
1234
|
+
self.option.new_jm_client = hook_new_jm_client
|
|
1235
|
+
|
|
1236
|
+
def request_with_retry(self,
|
|
1237
|
+
client,
|
|
1238
|
+
request,
|
|
1239
|
+
url,
|
|
1240
|
+
is_image,
|
|
1241
|
+
**kwargs,
|
|
1242
|
+
):
|
|
1243
|
+
pass
|
|
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
|