Skip to content

Commit c856b49

Browse files
authored
v2.5.16: 新增插件【replace_path_string】可直接对下载路径做文本替换; 【img2pdf】插件支持对整个本子合并为一个pdf; 增加禁漫API HTTP状态码的检查; 优化文档. (#261)
1 parent e3ac598 commit c856b49

12 files changed

+195
-44
lines changed

assets/docs/sources/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@
3535

3636
## 自定义
3737
- [下载文件夹名](tutorial/9_custom_download_dir_name.md)
38-
- [日志](tutorial/9_custom_download_dir_name.md)
38+
- [日志](tutorial/11_log_custom.md)
3939
- [模块](tutorial/4_module_custom.md)
4040

assets/docs/sources/option_file_syntax.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,13 @@ plugins:
130130
kwargs:
131131
allowed_orig_suffix: # 后缀列表,表示只想下载以.gif结尾的图片
132132
- .gif
133-
133+
- plugin: replace_path_string # 字符串替换插件,直接对下载文件夹的路径进行文本替换
134+
kwargs:
135+
replace:
136+
# {左边写你要替换的原文}: {右边写替换成什么文本}
137+
aaa: bbb
138+
kyockcho: きょくちょ
139+
134140
- plugin: client_proxy # 客户端实现类代理插件,不建议非开发人员使用
135141
kwargs:
136142
proxy_client_key: photo_concurrent_fetcher_proxy # 代理类的client_key
@@ -228,7 +234,15 @@ plugins:
228234
- plugin: img2pdf
229235
kwargs:
230236
pdf_dir: D:/pdf/ # pdf存放文件夹
231-
filename_rule: Pid # pdf命名规则
237+
filename_rule: Pid # pdf命名规则,P代表photo, id代表使用photo.id也就是章节id
238+
239+
# img2pdf也支持合并整个本子,把上方的after_photo改为after_album即可。
240+
# https://github.com/hect0x7/JMComic-Crawler-Python/discussions/258
241+
# 配置到after_album时,需要修改filename_rule参数,不能写Pxx只能写Axx示例如下
242+
- plugin: img2pdf
243+
kwargs:
244+
pdf_dir: D:/pdf/ # pdf存放文件夹
245+
filename_rule: Aname # pdf命名规则,A代表album, name代表使用album.name也就是本子名称
232246

233247
# 请注意⚠
234248
# 下方的j2p插件的功能不如img2pdf插件,不建议使用。

assets/docs/sources/tutorial/0_common_usage.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ album: JmAlbumDetail = client.get_album_detail('427413')
5353
def fetch(photo: JmPhotoDetail):
5454
# 章节实体类
5555
photo = client.get_photo_detail(photo.photo_id, False)
56-
56+
print(f'章节id: {photo.photo_id}')
57+
5758
# 图片实体类
5859
image: JmImageDetail
5960
for image in photo:
60-
print(image.img_url)
61+
print(f'图片url: {image.img_url}')
6162

6263

6364
# 多线程发起请求
@@ -67,6 +68,36 @@ multi_thread_launcher(
6768
)
6869
```
6970

71+
## jmcomic异常处理示例
72+
73+
```python
74+
from jmcomic import *
75+
76+
# 客户端
77+
client = JmOption.default().new_jm_client()
78+
79+
# 捕获jmcomic可能出现的异常
80+
try:
81+
# 请求本子实体类
82+
album: JmAlbumDetail = client.get_album_detail('427413')
83+
except MissingAlbumPhotoException as e:
84+
print(f'id={e.error_jmid}的本子不存在')
85+
86+
except JsonResolveFailException as e:
87+
print(f'解析json失败')
88+
# 响应对象
89+
resp = e.resp
90+
print(f'resp.text: {resp.text}, resp.status_code: {resp.status_code}')
91+
92+
except RequestRetryAllFailException as e:
93+
print(f'请求失败,重试次数耗尽')
94+
95+
except JmcomicException as e:
96+
# 捕获所有异常,用作兜底
97+
print(f'jmcomic遇到异常: {e}')
98+
```
99+
100+
70101
## 搜索本子
71102

72103
```python

assets/docs/sources/tutorial/9_custom_download_dir_name.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,46 @@
11
# 自定义下载文件夹名
22

3+
## 0. 最简单直接粗暴有效的方式
34

5+
使用插件`replace_path_string`
6+
7+
这个插件可以直接替换下载文件夹路径,配置示例如下(把如下配置放入option配置文件即可):
8+
9+
```yml
10+
plugins:
11+
after_init:
12+
- plugin: replace_path_string
13+
kwargs:
14+
replace:
15+
# {左边写你要替换的原文}: {右边写替换成什么文本}
16+
kyockcho: きょくちょ
17+
```
18+
该示例会把文件夹路径中所有`kyockcho`都变为`きょくちょ`,例如:
19+
20+
`D:/a/[kyockcho]本子名称 - kyockcho/` 改为↓
21+
22+
`D:/a/[きょくちょ]本子名称 - きょくちょ/`
23+
24+
---------------
25+
**_如果上述简单的文本替换无法满足你,或者你需要更多上下文写逻辑代码,那么下面的内容正适合你阅读。_**
26+
27+
## 1. DirRule机制简介
428

5-
## 1. DirRule简介
629

730
当你使用download_album下载本子时,本子会以一定的路径规则(DirRule)下载到你的磁盘上。
831

9-
你可以使用配置文件定制DirRule,例如下面的例子
32+
你可以使用配置文件定制DirRule,例如下面的例子
1033

1134
```yaml
1235
dir_rule:
36+
# 设定根目录 base_dir
1337
base_dir: D:/a/b/c/
14-
# 规则含义: 根目录 / 章节标题 / 图片文件
15-
rule: Bd_Ptitle # P表示章节,title表示使用章节的title字段
38+
rule: Bd / Ptitle # P表示章节,title表示使用章节的title字段
39+
# 这个规则的含义是,把图片下载到路径 {base_dir}/{Ptitle}/ 下
40+
# 即:根目录 / 章节标题 / 图片文件
1641
```
1742

18-
如果一个章节的名称(title)是ddd,则最后的下载文件夹结构为:
43+
例如,假设一个章节的名称(Ptitle)是ddd,则最后的下载文件夹结构为 `D:/a/b/c/ddd/`
1944

2045
```
2146
D:/a/b/c/ddd/00001.webp
@@ -24,6 +49,13 @@ D:/a/b/c/ddd/00003.webp
2449
...
2550
```
2651
52+
上述的Ptitle,P表示章节,title表示使用章节的title字段。
53+
54+
除了title,你还可以写什么?其实Ptitle表示的是jmcomic里的章节实体类 JmPhotoDetail 的属性。
55+
56+
最终能写什么,取决于JmPhotoDetail有哪些属性,建议使用IDE来获知这些属性,不过这需要你懂一些python基础。
57+
58+
除了Pxxx,你还可以写Axxx,表示这个章节所在的本子的属性xxx,详见本子实体类 JmAlbumDetail。
2759
2860
2961
## 2. 自定义字段名

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.5.15'
5+
__version__ = '2.5.16'
66

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

src/jmcomic/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
__DOWNLOAD_API_RET = Tuple[JmAlbumDetail, JmDownloader]
44

5+
56
def download_batch(download_api,
67
jm_id_iter: Union[Iterable, Generator],
78
option=None,

src/jmcomic/jm_client_impl.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init__(self,
2727
self.retry_times = retry_times
2828
self.domain_list = domain_list
2929
self.CLIENT_CACHE = None
30-
self.__username = None # help for favorite_folder method
30+
self._username = None # help for favorite_folder method
3131
self.enable_cache()
3232
self.after_init()
3333

@@ -412,7 +412,7 @@ def login(self,
412412
return resp
413413

414414
self['cookies'] = new_cookies
415-
self.__username = username
415+
self._username = username
416416

417417
return resp
418418

@@ -423,8 +423,8 @@ def favorite_folder(self,
423423
username='',
424424
) -> JmFavoritePage:
425425
if username == '':
426-
ExceptionTool.require_true(self.__username is not None, 'favorite_folder方法需要传username参数')
427-
username = self.__username
426+
ExceptionTool.require_true(self._username is not None, 'favorite_folder方法需要传username参数')
427+
username = self._username
428428

429429
resp = self.get_jm_html(
430430
f'/user/{username}/favorite/albums',
@@ -973,6 +973,11 @@ def raise_if_resp_should_retry(self, resp):
973973
# 例如图片请求
974974
return resp
975975

976+
code = resp.status_code
977+
if code >= 500:
978+
msg = JmModuleConfig.JM_ERROR_STATUS_CODE.get(code, f'HTTP状态码: {code}')
979+
ExceptionTool.raises_resp(f"禁漫API异常响应, {msg}", resp)
980+
976981
url = resp.request.url
977982

978983
if self.API_SCRAMBLE in url:

src/jmcomic/jm_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class JmModuleConfig:
123123
# JM的异常网页code
124124
JM_ERROR_STATUS_CODE = {
125125
403: 'ip地区禁止访问/爬虫被识别',
126+
500: '500: 禁漫服务器内部异常(可能是服务器过载,可以换个ip或稍后重试)',
126127
520: '520: Web server is returning an unknown error (禁漫服务器内部报错)',
127128
524: '524: The origin web server timed out responding to this request. (禁漫服务器处理超时)',
128129
}

src/jmcomic/jm_entity.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from functools import lru_cache
2+
13
from common import *
24

35
from .jm_config import *
@@ -400,6 +402,7 @@ def get_data_original_query_params(self, data_original_0: Optional[str]) -> str:
400402
def id(self):
401403
return self.photo_id
402404

405+
@lru_cache(None)
403406
def getindex(self, index) -> JmImageDetail:
404407
return self.create_image_detail(index)
405408

@@ -514,6 +517,7 @@ def create_photo_detail(self, index) -> JmPhotoDetail:
514517

515518
return photo
516519

520+
@lru_cache(None)
517521
def getindex(self, item) -> JmPhotoDetail:
518522
return self.create_photo_detail(item)
519523

src/jmcomic/jm_option.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,7 @@ def decide_image_save_dir(self, photo, ensure_exists=True) -> str:
270270
)
271271

272272
if ensure_exists:
273-
try:
274-
mkdir_if_not_exists(save_dir)
275-
except OSError as e:
276-
if e.errno == 36:
277-
# 目录名过长
278-
limit = JmModuleConfig.VAR_FILE_NAME_LENGTH_LIMIT
279-
jm_log('error', f'目录名过长,无法创建目录,强制缩短到{limit}个字符并重试')
280-
save_dir = save_dir[0:limit]
281-
mkdir_if_not_exists(save_dir)
273+
save_dir = JmcomicText.try_mkdir(save_dir)
282274

283275
return save_dir
284276

@@ -517,13 +509,21 @@ def merge_default_dict(cls, user_dict, default_dict=None):
517509

518510
# 下面的方法提供面向对象的调用风格
519511

520-
def download_album(self, album_id):
512+
def download_album(self,
513+
album_id,
514+
downloader=None,
515+
callback=None,
516+
):
521517
from .api import download_album
522-
download_album(album_id, self)
518+
download_album(album_id, self, downloader, callback)
523519

524-
def download_photo(self, photo_id):
520+
def download_photo(self,
521+
photo_id,
522+
downloader=None,
523+
callback=None
524+
):
525525
from .api import download_photo
526-
download_photo(photo_id, self)
526+
download_photo(photo_id, self, downloader, callback)
527527

528528
# 下面的方法为调用插件提供支持
529529

0 commit comments

Comments
 (0)