Skip to content

Commit 12351dd

Browse files
authored
v1.5.0: 优化JmcomicClient的配置流程、缓存启用,模块配置更加清晰。 (#12)
1 parent ca59399 commit 12351dd

File tree

8 files changed

+100
-59
lines changed

8 files changed

+100
-59
lines changed

src/jmcomic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
# 被依赖方 <--- 使用方
33
# config <--- entity <--- toolkit <--- client <--- service <--- option
44

5-
__version__ = '1.4.0'
5+
__version__ = '1.5.0'
66

77
from .api import *

src/jmcomic/api.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -131,37 +131,17 @@ def download_image(index, img_detail, debug_topic='download_images_of_photo'):
131131
)
132132

133133

134-
def renew_jm_default_domain():
135-
"""
136-
由于禁漫的域名经常变化,调用此方法可以获取一个当前可用的最新的域名 domain,
137-
并且设置把 domain 设置为禁漫模块的默认域名。
138-
这样一来,配置文件也不用配置域名了,一切都在运行时动态获取。
139-
"""
140-
domain = JmcomicText.parse_to_jm_domain(JmModuleConfig.get_jmcomic_url())
141-
JmModuleConfig.DOMAIN = domain
142-
return domain
143-
144-
145134
def build_client(option: Optional[JmOption]) -> Tuple[JmOption, JmcomicClient]:
146135
"""
147136
处理option的判空,并且创建jm_client
148137
"""
149138
if option is None:
150139
option = JmOption.default()
151-
option.client_config['domain'] = renew_jm_default_domain()
140+
152141
jm_client = option.build_jm_client()
153142
return option, jm_client
154143

155144

156145
def create_option(filepath: str) -> JmOption:
157-
"""
158-
创建 JmOption,同时检查域名是否配置,未配置则补上配置
159-
@param filepath:
160-
@return:
161-
"""
162146
option = JmOption.create_from_file(filepath)
163-
client_config = option.client_config
164-
key = 'domain'
165-
if client_config.get(key, None) is None or client_config[key] is None:
166-
client_config[key] = renew_jm_default_domain()
167147
return option

src/jmcomic/jm_client.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ def search_album(self, search_query, main_tag=0) -> JmSearchPage:
120120
# -- 对象方法 --
121121

122122
def of_api_url(self, api_path):
123-
return f"{JmModuleConfig.HTTP}{self.domain}{api_path}"
123+
return f"{JmModuleConfig.PROT}{self.domain}{api_path}"
124124

125125
def jm_get(self, url, is_api=True, require_200=True, **kwargs):
126126
"""
@@ -157,6 +157,28 @@ def is_empty_image(cls, resp):
157157
def img_is_not_need_to_decode(cls, data_original: str, _resp):
158158
return data_original.endswith('.gif')
159159

160+
# noinspection PyAttributeOutsideInit
161+
def enable_cache(self):
162+
def wrap_func_cache(func_name, cache_dict_name):
163+
if hasattr(self, cache_dict_name):
164+
return
165+
166+
cache_dict = {}
167+
setattr(self, cache_dict_name, cache_dict)
168+
169+
# 重载本对象的方法
170+
func = getattr(self, func_name)
171+
wrap_func = enable_cache(
172+
cache_dict=cache_dict,
173+
cache_hit_msg=f'命中 {cache_dict_name} ' + '→ [{}]]',
174+
cache_miss_msg=f'缺失 {cache_dict_name} ' + '← [{}]',
175+
)(func)
176+
177+
setattr(self, func_name, wrap_func)
178+
179+
wrap_func_cache('get_photo_detail', 'album_cache_dict')
180+
wrap_func_cache('get_album_detail', 'photo_cache_dict')
181+
160182

161183
# 爬取策略
162184
class FetchStrategy:

src/jmcomic/jm_config.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
class JmModuleConfig:
22
# 网站相关
3-
HTTP = "https://"
4-
DOMAIN = "jmcomic1.group" # jmcomic默认域名
5-
JM_REDIRECT_URL = f'{HTTP}jm365.xyz/3YeBdF' # 永久網域,怕走失的小伙伴收藏起来
6-
JM_PUB_URL = f'{HTTP}jmcomic1.bet'
7-
JM_CDN_IMAGE_URL_TEMPLATE = HTTP + 'cdn-msp.{domain}/media/photos/{photo_id}/{index:05}{suffix}' # index 从1开始
3+
PROT = "https://"
4+
_DOMAIN = None
5+
JM_REDIRECT_URL = f'{PROT}jm365.xyz/3YeBdF' # 永久網域,怕走失的小伙伴收藏起来
6+
JM_PUB_URL = f'{PROT}jmcomic1.bet'
7+
JM_CDN_IMAGE_URL_TEMPLATE = PROT + 'cdn-msp.{domain}/media/photos/{photo_id}/{index:05}{suffix}' # index 从1开始
88
JM_SERVER_ERROR_HTML = "Could not connect to mysql! Please check your database settings!"
99
JM_IMAGE_SUFFIX = ['.jpg', '.webp', '.png', '.gif']
1010

@@ -26,9 +26,21 @@ class JmModuleConfig:
2626
jm_client_caches = {}
2727

2828
@classmethod
29-
def default_headers(cls):
29+
def domain(cls, postman=None):
30+
"""
31+
由于禁漫的域名经常变化,调用此方法可以获取一个当前可用的最新的域名 domain,
32+
并且设置把 domain 设置为禁漫模块的默认域名。
33+
这样一来,配置文件也不用配置域名了,一切都在运行时动态获取。
34+
"""
35+
if cls._DOMAIN is None:
36+
cls._DOMAIN = cls.get_jmcomic_url(postman).replace(cls.PROT, '')
37+
38+
return cls._DOMAIN # jmcomic默认域名
39+
40+
@classmethod
41+
def headers(cls, authority=None):
3042
return {
31-
'authority': cls.DOMAIN,
43+
'authority': authority or cls.domain(),
3244
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,'
3345
'application/signed-exchange;v=b3;q=0.7',
3446
'accept-language': 'zh-CN,zh;q=0.9',
@@ -55,16 +67,16 @@ def disable_jm_debug(cls):
5567
cls.enable_jm_debug = False
5668

5769
@classmethod
58-
def get_jmcomic_url(cls):
70+
def get_jmcomic_url(cls, postman=None):
5971
"""
6072
访问禁漫的永久网域,从而得到一个可用的禁漫网址,
6173
"""
62-
from common import Postmans
74+
if postman is None:
75+
from common import Postmans
76+
postman = Postmans.get_impl_clazz('cffi') \
77+
.create(headers=cls.headers(cls.JM_REDIRECT_URL))
6378

64-
domain = Postmans \
65-
.get_impl_clazz('cffi') \
66-
.create(headers=cls.default_headers()) \
67-
.with_wrap_resp() \
79+
domain = postman.with_wrap_resp() \
6880
.get(cls.JM_REDIRECT_URL, allow_redirects=False) \
6981
.redirect_url
7082

src/jmcomic/jm_entity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def keyword_list(self) -> List[str]:
131131

132132
@property
133133
def album_id(self) -> str:
134-
return self.photo_id if self.is_single_album else self._series_id
134+
return self.photo_id if self.is_single_album else str(self._series_id)
135135

136136
@property
137137
def album_index(self) -> int:

src/jmcomic/jm_option.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,10 @@ def create_from_file(cls, filepath: str) -> 'JmOption':
317317
@classmethod
318318
def default_client_config(cls):
319319
return {
320-
'domain': JmModuleConfig.DOMAIN,
320+
'domain': JmModuleConfig.domain(),
321321
'meta_data': {
322322
'cookies': None,
323-
'headers': JmModuleConfig.default_headers(),
323+
'headers': JmModuleConfig.headers(),
324324
'allow_redirects': True,
325325
},
326326
'postman_type_list': [
@@ -364,9 +364,13 @@ def build_jm_client(self) -> JmcomicClient:
364364

365365
def new_jm_client(self) -> JmcomicClient:
366366
meta_data = self.client_config['meta_data']
367+
postman_clazz = Postmans.get_impl_clazz(self.client_config.get('postman_type', 'cffi'))
368+
proxies = None
369+
domain = None
370+
postman: Optional[Postman] = None
367371

368-
# 处理代理
369-
def handle_proxies(key='proxies'):
372+
def decide_proxies(key='proxies'):
373+
nonlocal proxies
370374
proxies = meta_data.get(key, None)
371375

372376
# 无代理,或代理已配置好好的
@@ -381,25 +385,46 @@ def handle_proxies(key='proxies'):
381385

382386
meta_data[key] = proxies
383387

384-
# 处理 headers
388+
def decide_domain(key='domain') -> str:
389+
nonlocal domain
390+
domain = self.client_config.get(key, None)
391+
if domain is None:
392+
temp_postman = postman_clazz.create(
393+
headers=JmModuleConfig.headers(JmModuleConfig.JM_REDIRECT_URL),
394+
proxies=proxies,
395+
)
396+
domain = JmModuleConfig.domain(temp_postman)
397+
398+
domain = JmcomicText.parse_to_jm_domain(domain)
399+
self.client_config[key] = domain
400+
return domain
401+
385402
def handle_headers(key='headers'):
386403
headers = meta_data.get(key, None)
387404
if headers is None or (not isinstance(headers, dict)) or len(headers) == 0:
388-
meta_data[key] = JmModuleConfig.default_headers()
405+
# 未配置headers,使用默认headers
406+
headers = JmModuleConfig.headers()
389407

390-
# 处理【特殊配置项】
391-
handle_proxies()
392-
handle_headers()
408+
meta_data[key] = headers
393409

394-
# 决定Postman的实现类,根据配置项 client_config.postman
395-
postman_clazz = Postmans.get_impl_clazz(self.client_config.get('postman_type', 'cffi'))
396-
# 决定域名
397-
domain = self.client_config.get('domain', JmModuleConfig.DOMAIN)
410+
def handle_postman():
411+
nonlocal postman
412+
postman = postman_clazz(meta_data)
413+
414+
# 1. 决定 代理
415+
decide_proxies()
416+
# 2. 指定 JM域名
417+
decide_domain()
418+
# 3. 处理 headers
419+
handle_headers()
420+
# 4. 创建 postman
421+
handle_postman()
398422

399423
jm_debug('创建JmcomicClient', f'使用域名: {domain},使用Postman实现: {postman_clazz}')
400-
# 创建 JmcomicClient 实例
424+
425+
# 创建 JmcomicClient 对象
401426
client = JmcomicClient(
402-
postman=postman_clazz(meta_data),
427+
postman=postman,
403428
domain=domain,
404429
retry_times=self.client_config.get('retry_times', None)
405430
)
@@ -413,7 +438,7 @@ def handle_headers(key='headers'):
413438
def build_cdn_option(self, use_multi_thread_strategy=True):
414439

415440
return CdnConfig.create(
416-
cdn_domain=self.client_config.get('domain', JmModuleConfig.DOMAIN),
441+
cdn_domain=self.client_config.get('domain', JmModuleConfig.domain()),
417442
fetch_strategy=MultiThreadFetch if use_multi_thread_strategy else InOrderFetch,
418443
cdn_image_suffix=None,
419444
use_cache=self.download_use_disk_cache,

tests/test_jmcomic/__init__.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ def setUpClass(cls):
3535
# 设置 JmOption,JmcomicClient
3636
option = cls.use_option('option_test.yml')
3737
cls.option = option
38+
cls.client = option.build_jm_client()
3839

39-
client = option.build_jm_client()
40-
# enable cache
41-
client.get_photo_detail = enable_cache()(client.get_photo_detail)
42-
client.get_album_detail = enable_cache()(client.get_album_detail)
43-
cls.client = client
40+
# 启用 JmClientClient 缓存
41+
cls.enable_client_cache()
4442

4543
# 跨平台设置
4644
cls.adapt_os()
@@ -79,3 +77,7 @@ def adapt_linux(cls):
7977
@classmethod
8078
def adapt_macos(cls):
8179
pass
80+
81+
@classmethod
82+
def enable_client_cache(cls):
83+
cls.client.enable_cache()

tests/test_jmcomic/test_jm_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def decide_image_filepath(self,
5555
photo_detail: JmPhotoDetail,
5656
index: int,
5757
) -> StrNone:
58-
return workspace(f'{time_stamp()}_{photo_detail[index].img_file_name}.test.png')
58+
return workspace(f'advice_{photo_detail[index].img_file_name}.test.png')
5959

6060
option = self.option
6161
option.register_advice(MyAdvice())

0 commit comments

Comments
 (0)