Skip to content

Commit a847b92

Browse files
authored
v2.2.2: 实现两个内置插件:find_update和zip,优化文档和代码示例 (#118) (#95)
1 parent c6e8d69 commit a847b92

14 files changed

+628
-85
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,11 @@ on:
44
workflow_dispatch:
55
push:
66
branches: [ "dev" ]
7-
paths-ignore:
8-
- 'src/**/__init__.py'
9-
- '.github/workflows/*'
10-
- 'usage/workflow_download.py'
11-
- 'assets/config/option_workflow_download.yml'
12-
- 'assets/docs/*'
7+
paths:
8+
- 'src/**/*.py'
9+
- 'test/**/*.py'
10+
- '.github/workflows/test.yml'
11+
- 'assets/config/option_test.yml'
1312

1413
jobs:
1514
test: # This code is based on https://github.com/gaogaotiantian/viztracer/blob/master/.github/workflows/python-package.yml

README.md

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
**友情提示:珍爱JM,为了减轻JM的服务器压力,请不要一次性爬取太多本子,西门🙏🙏🙏**.
88

9+
10+
911
## 安装教程
1012

1113
* 通过pip官方源安装(推荐,并且更新也是这个命令)
@@ -19,6 +21,8 @@
1921
pip install -e ./
2022
```
2123

24+
25+
2226
## 快速上手
2327

2428
使用下面的两行代码,即可实现功能:把某个本子(album)里的所有章节(photo)下载到本地
@@ -33,15 +37,28 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
3337
# 如果你想要配置,请参考文件 assets/config/常用配置介绍.yml
3438
```
3539

36-
进阶使用可以参考本repo下usage文件夹内的示例代码文件:
40+
41+
42+
## 进阶使用
43+
44+
进阶使用可以参考本repo下usage文件夹内的示例代码文件,下面是各个文件的作用,你可以挑感兴趣的阅读:
3745

3846
- API上手介绍: `getting_started.py`
3947
- 使用API实现简单功能: `usage_simple.py`
48+
- 演示jmcomic模块的可自定义功能点: `usage_custom.py`
4049
- 使用API的Filter过滤功能: `usage_feature_filter.py`
50+
- 演示jmcomic模块的Plugin插件体系: `usage_feature_plugin.py`
51+
- 演示一个综合使用实例: `usage_advanced.py`
52+
- 包括6个功能需求的介绍、实现方案和完整运行日志
53+
- 实现方案非常简洁,充分jmcomic的便利性,以及强大的插件扩展机制
54+
55+
56+
以及一些趣味用法:
57+
4158
- 测试你的ip可以访问哪些禁漫域名: `pick_domain.py`
4259
- 基于GitHub Actions下载本子: `workflow_download.py`
43-
- 演示jmcomic模块的自定义功能点: `usage_custom.py`
44-
- 演示jmcomic模块的Plugin插件体系: `usage_plugin.py`
60+
61+
4562

4663
## 项目特点
4764

@@ -53,7 +70,7 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
5370
- 配置点有:`是否使用磁盘缓存` `并发下载图片数` `图片类型转换` `下载路径` `请求元信息(headers,cookies,proxies)`
5471
- **可扩展性强**
5572
- **支持Plugin插件,可以方便地扩展功能,以及使用别人的插件**
56-
- 目前内置支持的插件`登录插件``硬件占用监控插件`
73+
- 目前内置支持的插件有`登录插件` `硬件占用监控插件` `只下载新章插件` `压缩文件插件`
5774
- 支持自定义本子/章节/图片下载前后的回调函数
5875
- 支持自定义debug日志的开关/格式
5976
- 支持自定义Downloader/Option/Client/实体类
@@ -62,11 +79,15 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
6279
- **多线程下载**(可细化到一图一线程,效率极高)
6380
- 跟进了JM最新的图片分割算法(2023-02-08)
6481

82+
83+
6584
## 使用小说明
6685

6786
* Python >= 3.7
6887
* 个人项目,文档和示例会有不及时之处,可以Issue提问
6988

89+
90+
7091
## 项目文件夹介绍
7192

7293
* assets:存放一些非代码的资源文件
@@ -79,6 +100,8 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
79100
* tests:测试目录,存放测试代码,使用unittest
80101
* usage:用法目录,存放示例/使用代码
81102

103+
104+
82105
## 感谢以下项目
83106

84107
### 图片分割算法代码+禁漫移动端API

assets/config/option_plugin.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,21 @@ plugin:
55
- plugin: usage-log # 实时打印硬件占用率的插件
66
kwargs:
77
interval: 0.5 # 间隔时间
8-
enable_warning: true
8+
enable_warning: true # 占用过大时发出预警
99

1010
- plugin: login # 登录插件
1111
kwargs:
1212
username: un
1313
password: pw
14+
15+
- plugin: find_update # 只下载新章插件
16+
kwargs:
17+
145504: 290266 # 下载本子145504的章节290266以后的新章
18+
19+
after_album:
20+
- plugin: zip # 压缩文件插件
21+
kwargs:
22+
level: photo # 按照章节,一个章节一个压缩文件
23+
filename_rule: Ptitle # 压缩文件的命名规则
24+
zip_dir: D:/GitProject/dev/pip/jmcomic/ # 压缩文件存放的文件夹
25+
delete_original_file: true # 压缩成功后,删除所有原文件和文件夹

src/jmcomic/__init__.py

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

5-
__version__ = '2.2.1'
5+
__version__ = '2.2.2'
66

77
from .api import *
88
from .jm_plugin import *

src/jmcomic/api.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
def download_batch(download_api,
55
jm_id_iter: Union[Iterable, Generator],
66
option=None,
7+
downloader=None,
78
):
89
"""
910
批量下载 album / photo
@@ -12,6 +13,7 @@ def download_batch(download_api,
1213
@param download_api: 下载api
1314
@param jm_id_iter: jmid (album_id, photo_id) 的迭代器
1415
@param option: 下载选项,对所有的jmid使用同一个,默认是 JmOption.default()
16+
@param downloader: 下载器类
1517
"""
1618
from common import multi_thread_launcher
1719

@@ -23,41 +25,45 @@ def download_batch(download_api,
2325
JmcomicText.parse_to_album_id(jmid)
2426
for jmid in jm_id_iter
2527
),
26-
apply_each_obj_func=lambda aid: download_api(aid, option),
28+
apply_each_obj_func=lambda aid: download_api(aid, option, downloader),
2729
)
2830

2931

30-
def download_album(jm_album_id, option=None):
32+
def download_album(jm_album_id, option=None, downloader=None):
3133
"""
3234
下载一个本子
3335
@param jm_album_id: 禁漫的本子的id,类型可以是str/int/iterable[str]。
3436
如果是iterable[str],则会调用 download_album_batch
3537
@param option: 下载选项,为空默认是 JmOption.default()
38+
@param downloader: 下载器类
3639
"""
3740

3841
if not isinstance(jm_album_id, (str, int)):
39-
return download_batch(download_album, jm_album_id, option)
42+
return download_batch(download_album, jm_album_id, option, downloader)
4043

41-
with new_downloader(option) as dler:
44+
with new_downloader(option, downloader) as dler:
4245
dler.download_album(jm_album_id)
4346

4447

45-
def download_photo(jm_photo_id, option=None):
48+
def download_photo(jm_photo_id, option=None, downloader=None):
4649
"""
4750
下载一个章节
4851
"""
4952
if not isinstance(jm_photo_id, (str, int)):
5053
return download_batch(download_photo, jm_photo_id, option)
5154

52-
with new_downloader(option) as dler:
55+
with new_downloader(option, downloader) as dler:
5356
dler.download_photo(jm_photo_id)
5457

5558

56-
def new_downloader(option=None):
59+
def new_downloader(option=None, downloader=None) -> JmDownloader:
5760
if option is None:
5861
option = JmModuleConfig.option_class().default()
5962

60-
return JmModuleConfig.downloader_class()(option)
63+
if downloader is None:
64+
downloader = JmModuleConfig.downloader_class()
65+
66+
return downloader(option)
6167

6268

6369
def create_option(filepath):

src/jmcomic/jm_client_impl.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class AbstractJmClient(
55
JmcomicClient,
66
PostmanProxy,
77
):
8+
client_key: None
89

910
def __init__(self,
1011
postman: Postman,
@@ -153,6 +154,7 @@ def fallback(self, request, url, domain_index, retry_count, **kwargs):
153154

154155
# 基于网页实现的JmClient
155156
class JmHtmlClient(AbstractJmClient):
157+
client_key = 'html'
156158

157159
def get_album_detail(self, album_id) -> JmAlbumDetail:
158160
# 参数校验
@@ -366,6 +368,7 @@ def check_special_http_code(cls, resp):
366368

367369

368370
class JmApiClient(AbstractJmClient):
371+
client_key = 'api'
369372
API_SEARCH = '/search'
370373

371374
def search_album(self, search_query, main_tag=0, page=1) -> JmApiResp:
@@ -437,5 +440,5 @@ def save_image_resp(self, *args, **kwargs):
437440
self.future_list.append(future)
438441

439442

440-
JmModuleConfig.CLASS_CLIENT_IMPL['html'] = JmHtmlClient
441-
JmModuleConfig.CLASS_CLIENT_IMPL['api'] = JmApiClient
443+
JmModuleConfig.register_client(JmHtmlClient)
444+
JmModuleConfig.register_client(JmApiClient)

src/jmcomic/jm_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ def option_default_dict(cls) -> dict:
297297
def register_plugin(cls, plugin_class):
298298
cls.plugin_registry[plugin_class.plugin_key] = plugin_class
299299

300+
@classmethod
301+
def register_client(cls, client_class):
302+
cls.CLASS_CLIENT_IMPL[client_class.client_key] = client_class
303+
300304

301305
jm_debug = JmModuleConfig.jm_debug
302306
disable_jm_debug = JmModuleConfig.disable_jm_debug

src/jmcomic/jm_downloader.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def before_photo(self, photo: JmPhotoDetail):
3838

3939
def after_photo(self, photo: JmPhotoDetail):
4040
jm_debug('photo.after',
41-
f'章节下载完成: {photo.id} ({photo.album_id}[{photo.index}/{len(photo.from_album)}])')
41+
f'章节下载完成: [{photo.id}] ({photo.album_id}[{photo.index}/{len(photo.from_album)}])')
4242

4343
def before_image(self, image: JmImageDetail, img_save_path):
4444
if image.is_exists:
@@ -65,6 +65,9 @@ def __init__(self, option: JmOption) -> None:
6565
self.use_cache = self.option.download_cache
6666
self.decode_image = self.option.download_image_decode
6767

68+
# 收集所有下载的image,为plugin提供数据
69+
self.all_downloaded: Dict[JmAlbumDetail, Dict[JmPhotoDetail, List[Tuple[str, JmImageDetail]]]] = {}
70+
6871
def download_album(self, album_id):
6972
client = self.client_for_album(album_id)
7073
album = client.get_album_detail(album_id)
@@ -121,6 +124,9 @@ def execute_by_condition(self,
121124
iter_objs = self.filter_iter_objs(iter_objs)
122125
count_real = len(iter_objs)
123126

127+
if count_real == 0:
128+
return
129+
124130
if count_batch >= count_real:
125131
# 一个图/章节 对应 一个线程
126132
multi_thread_launcher(
@@ -162,6 +168,34 @@ def client_for_photo(self, jm_photo_id) -> JmcomicClient:
162168
"""
163169
return self.option.build_jm_client()
164170

171+
# 下面是回调方法
172+
173+
def before_album(self, album: JmAlbumDetail):
174+
super().before_album(album)
175+
self.all_downloaded.setdefault(album, {})
176+
177+
def before_photo(self, photo: JmPhotoDetail):
178+
super().before_photo(photo)
179+
self.all_downloaded.setdefault(photo.from_album, {})
180+
self.all_downloaded[photo.from_album].setdefault(photo, [])
181+
182+
def after_album(self, album: JmAlbumDetail):
183+
super().after_album(album)
184+
self.option.call_all_plugin(
185+
'after_album',
186+
album=album,
187+
downloader=self,
188+
)
189+
190+
def after_image(self, image: JmImageDetail, img_save_path):
191+
super().after_image(image, img_save_path)
192+
photo = image.from_photo
193+
album = photo.from_album
194+
195+
self.all_downloaded.get(album).get(photo).append((img_save_path, image))
196+
197+
# 下面是对with语法的支持
198+
165199
def __enter__(self):
166200
return self
167201

0 commit comments

Comments
 (0)