Skip to content

Commit 9a5c5d1

Browse files
authored
v2.1.5: 重构代码结构,使得更简洁可扩展 (#81)
1 parent 7b2e997 commit 9a5c5d1

10 files changed

+216
-150
lines changed

requirements-dev.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,3 @@ commonX
22
curl_cffi
33
PyYAML
44
Pillow
5-
6-
# for test
7-
pyperclip

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 <--- option
44

5-
__version__ = '2.1.4'
5+
__version__ = '2.1.5'
66

77
from .api import *

src/jmcomic/api.py

Lines changed: 61 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,118 +15,103 @@ def download_album(jm_album_id, option=None):
1515
option, jm_client = build_client(option)
1616
album: JmAlbumDetail = jm_client.get_album_detail(jm_album_id)
1717

18-
jm_debug('album',
19-
f'本子获取成功: [{album.id}], '
20-
f'作者: [{album.author}], '
21-
f'章节数: [{len(album)}], '
22-
f'标题: [{album.title}], '
23-
)
24-
25-
def download_photo(photo: JmPhotoDetail,
26-
debug_topic='photo',
27-
):
28-
jm_client.check_photo(photo)
29-
30-
jm_debug(debug_topic,
31-
f'开始下载章节: {photo.id} ({photo.album_id}[{photo.index}/{len(album)}]), '
32-
f'标题: [{photo.title}], '
33-
f'图片数为[{len(photo)}]'
34-
)
35-
36-
download_by_photo_detail(photo, option)
37-
38-
jm_debug(debug_topic,
39-
f'章节下载完成: {photo.id} ({photo.album_id}[{photo.index}/{len(album)}])'
40-
)
41-
42-
thread_pool_executor(
43-
iter_objs=album,
44-
apply_each_obj_func=download_photo,
45-
)
46-
47-
jm_debug('album', f'本子下载完成: [{album.id}]')
48-
49-
50-
def download_album_batch(jm_album_id_iter: Union[Iterable, Generator],
51-
option=None,
52-
wait_finish=True,
53-
) -> List[Thread]:
54-
"""
55-
批量下载album,每个album一个线程,使用的是同一个option。
56-
57-
@param jm_album_id_iter: album_id的可迭代对象
58-
@param option: 下载选项,为空默认是 JmOption.default()
59-
@param wait_finish: 是否要等待这些下载线程全部完成
60-
@return 返回值是List[Thread],里面是每个下载漫画的线程。
61-
"""
62-
if option is None:
63-
option = JmOption.default()
64-
65-
return thread_pool_executor(
66-
iter_objs=((album_id, option) for album_id in jm_album_id_iter),
67-
apply_each_obj_func=download_album,
68-
wait_finish=wait_finish,
18+
option.before_album(album)
19+
execute_by_condition(
20+
iter_obj=album,
21+
apply=lambda photo: download_by_photo_detail(photo, option),
22+
count_batch=option.decide_photo_batch_count(album)
6923
)
24+
option.after_album(album)
7025

7126

7227
def download_photo(jm_photo_id, option=None):
7328
"""
7429
下载一个本子的一章,入口api
7530
"""
7631
option, jm_client = build_client(option)
77-
photo_detail = jm_client.get_photo_detail(jm_photo_id)
78-
download_by_photo_detail(photo_detail, option)
32+
photo = jm_client.get_photo_detail(jm_photo_id)
33+
download_by_photo_detail(photo, option)
7934

8035

81-
def download_by_photo_detail(photo_detail: JmPhotoDetail,
82-
option=None,
83-
):
36+
def download_by_photo_detail(photo: JmPhotoDetail, option=None):
8437
"""
85-
下载一个本子的一章,根据 photo_detail
86-
@param photo_detail: 本子章节信息
38+
下载一个本子的一章,根据 photo
39+
@param photo: 本子章节信息
8740
@param option: 选项
8841
"""
8942
option, jm_client = build_client(option)
9043

9144
# 下载准备
9245
use_cache = option.download_cache
9346
decode_image = option.download_image_decode
94-
jm_client.check_photo(photo_detail)
47+
jm_client.check_photo(photo)
9548

9649
# 下载每个图片的函数
97-
def download_image(index, image: JmImageDetail, debug_topic='image'):
98-
img_save_path = option.decide_image_filepath(photo_detail, index)
99-
debug_tag = f'{image.aid}/{image.filename} [{index + 1}/{len(photo_detail)}]'
50+
def download_image(image: JmImageDetail):
51+
img_save_path = option.decide_image_filepath(image)
10052

10153
# 已下载过,缓存命中
10254
if use_cache is True and file_exists(img_save_path):
103-
jm_debug(debug_topic,
104-
f'图片已存在: {debug_tag} ← [{img_save_path}]'
105-
)
55+
image.is_exists = True
10656
return
10757

108-
# 开始下载
58+
option.before_image(image, img_save_path)
10959
jm_client.download_by_image_detail(
11060
image,
11161
img_save_path,
11262
decode_image=decode_image,
11363
)
64+
option.after_image(image, img_save_path)
65+
66+
option.before_photo(photo)
67+
execute_by_condition(
68+
iter_obj=photo,
69+
apply=download_image,
70+
count_batch=option.decide_image_batch_count(photo)
71+
)
72+
option.before_photo(photo)
11473

115-
jm_debug(debug_topic,
116-
f'图片下载完成: {debug_tag}, [{image.img_url}] → [{img_save_path}]'
117-
)
11874

119-
batch = option.download_threading_batch_count
120-
if batch <= 0:
75+
def download_album_batch(jm_album_id_iter: Union[Iterable, Generator],
76+
option=None,
77+
wait_finish=True,
78+
) -> List[Thread]:
79+
"""
80+
批量下载album,每个album一个线程,使用的是同一个option。
81+
82+
@param jm_album_id_iter: album_id的可迭代对象
83+
@param option: 下载选项,为空默认是 JmOption.default()
84+
@param wait_finish: 是否要等待这些下载线程全部完成
85+
@return 返回值是List[Thread],里面是每个下载漫画的线程。
86+
"""
87+
if option is None:
88+
option = JmOption.default()
89+
90+
return thread_pool_executor(
91+
iter_objs=((album_id, option) for album_id in jm_album_id_iter),
92+
apply_each_obj_func=download_album,
93+
wait_finish=wait_finish,
94+
)
95+
96+
97+
def execute_by_condition(iter_obj, apply: Callable, count_batch: int):
98+
"""
99+
章节/图片的下载调度逻辑
100+
"""
101+
count_real = len(iter_obj)
102+
103+
if count_batch >= count_real:
104+
# 一图一线程
121105
multi_thread_launcher(
122-
iter_objs=enumerate(photo_detail),
123-
apply_each_obj_func=download_image,
106+
iter_objs=iter_obj,
107+
apply_each_obj_func=apply,
124108
)
125109
else:
110+
# 创建batch个线程的线程池,当图片数>batch时要等待。
126111
thread_pool_executor(
127-
iter_objs=enumerate(photo_detail),
128-
apply_each_obj_func=download_image,
129-
max_workers=batch,
112+
iter_objs=iter_obj,
113+
apply_each_obj_func=apply,
114+
max_workers=count_batch,
130115
)
131116

132117

src/jmcomic/jm_client_impl.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def post(self, url, **kwargs):
3131
return self.request_with_retry(self.postman.post, url, **kwargs)
3232

3333
def of_api_url(self, api_path, domain):
34-
return f'{JmModuleConfig.PROT}{domain}{api_path}'
34+
return JmcomicText.format_url(api_path, domain)
3535

3636
def request_with_retry(self,
3737
request,
@@ -52,9 +52,11 @@ def request_with_retry(self,
5252
self.fallback(request, url, domain_index, retry_count, **kwargs)
5353

5454
if url.startswith('/'):
55-
# path
56-
domain = self.domain_list[domain_index]
57-
url = self.of_api_url(url, domain)
55+
# path → url
56+
url = self.of_api_url(
57+
api_path=url,
58+
domain=self.domain_list[domain_index],
59+
)
5860
jm_debug('api', url)
5961
else:
6062
# 图片url
@@ -154,13 +156,13 @@ def get_photo_detail(self, photo_id, fetch_album=True) -> JmPhotoDetail:
154156
resp = self.get_jm_html(f"/photo/{photo_id}")
155157

156158
# 用 JmcomicText 解析 html,返回实体类
157-
photo_detail = JmcomicText.analyse_jm_photo_html(resp.text)
159+
photo = JmcomicText.analyse_jm_photo_html(resp.text)
158160

159161
# 一并获取该章节的所处本子
160162
if fetch_album is True:
161-
photo_detail.from_album = self.get_album_detail(photo_detail.album_id)
163+
photo.from_album = self.get_album_detail(photo.album_id)
162164

163-
return photo_detail
165+
return photo
164166

165167
def search_album(self, search_query, main_tag=0, page=1) -> JmSearchPage:
166168
params = {

src/jmcomic/jm_client_interface.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,28 @@ def of_api_url(self, api_path, domain):
160160
def enable_cache(self, debug=False):
161161
raise NotImplementedError
162162

163-
def check_photo(self, photo_detail: JmPhotoDetail):
163+
def check_photo(self, photo: JmPhotoDetail):
164+
"""
165+
photo来源有两种:
166+
1. album[?]
167+
2. client.get_photo_detail(?)
168+
169+
其中,只有[2]是可以包含下载图片的url信息的。
170+
本方法会检查photo是不是[1],
171+
如果是[1],通过请求获取[2],然后把2中的一些重要字段更新到1中
172+
173+
@param photo: 被检查的JmPhotoDetail对象
174+
"""
164175
# 检查 from_album
165-
if photo_detail.from_album is None:
166-
photo_detail.from_album = self.get_album_detail(photo_detail.album_id)
176+
if photo.from_album is None:
177+
photo.from_album = self.get_album_detail(photo.album_id)
167178

168179
# 检查 page_arr 和 data_original_domain
169-
if photo_detail.page_arr is None or photo_detail.data_original_domain is None:
170-
new = self.get_photo_detail(photo_detail.photo_id, False)
171-
new.from_album = photo_detail.from_album
172-
photo_detail.__dict__.update(new.__dict__)
180+
if photo.page_arr is None or photo.data_original_domain is None:
181+
new = self.get_photo_detail(photo.photo_id, False)
182+
new.from_album = photo.from_album
183+
photo.__dict__.update(new.__dict__)
184+
173185

174186
class JmUserClient:
175187

@@ -232,14 +244,14 @@ def download_image(self,
232244
resp.transfer_to(img_save_path, scramble_id, decode_image, img_url)
233245

234246
def download_by_image_detail(self,
235-
img_detail: JmImageDetail,
247+
image: JmImageDetail,
236248
img_save_path,
237249
decode_image=True,
238250
):
239251
self.download_image(
240-
img_detail.download_url,
252+
image.download_url,
241253
img_save_path,
242-
img_detail.scramble_id,
254+
image.scramble_id,
243255
decode_image=decode_image,
244256
)
245257

0 commit comments

Comments
 (0)