Skip to content

Commit 2225136

Browse files
authored
v2.6.17: 修复 download_photo 场景下的插件路径解析报错 KeyError(fix #523) (#524)
1 parent 17fc58d commit 2225136

7 files changed

Lines changed: 70 additions & 16 deletions

File tree

requirements-dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ psutil
66
pycryptodome
77
requests
88
plugin_jm_server
9-
zhconv
9+
zhconv
10+
img2pdf

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.6.16'
5+
__version__ = '2.6.17'
66

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

src/jmcomic/jm_config.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class JmMagicConstants:
102102
APP_TOKEN_SECRET_2 = '18comicAPPContent'
103103
APP_DATA_SECRET = '185Hcomic3PAPP7R'
104104
API_DOMAIN_SERVER_SECRET = 'diosfjckwpqpdfjkvnqQjsik'
105-
APP_VERSION = '2.0.18'
105+
APP_VERSION = '2.0.19'
106106

107107

108108
# 模块级别共用配置
@@ -405,8 +405,8 @@ def get_fix_ts_token_tokenparam(cls):
405405
return ts, token, tokenparam
406406

407407
@classmethod
408-
def jm_log(cls, topic: str, msg: str, e: Exception = None):
409-
if cls.FLAG_ENABLE_JM_LOG is True:
408+
def jm_log(cls, topic: str, msg, e: Exception = None):
409+
if cls.FLAG_ENABLE_JM_LOG:
410410
executor = cls.EXECUTOR_LOG
411411
if e is None:
412412
executor(topic, msg)
@@ -440,7 +440,7 @@ def new_postman(cls, session=False, **kwargs):
440440

441441
from common import Postmans
442442

443-
if session is True:
443+
if session:
444444
return Postmans.new_session(**kwargs)
445445

446446
return Postmans.new_postman(**kwargs)

src/jmcomic/jm_option.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ def download_photo(self,
522522

523523
# 下面的方法为调用插件提供支持
524524

525-
def call_all_plugin(self, group: str, safe=True, **extra):
525+
def call_all_plugin(self, group: str, safe=None, **extra):
526526
plugin_list: List[dict] = self.plugins.get(group, [])
527527
if plugin_list is None or len(plugin_list) == 0:
528528
return
@@ -540,7 +540,7 @@ def call_all_plugin(self, group: str, safe=True, **extra):
540540
try:
541541
self.invoke_plugin(pclass, kwargs, extra, pinfo)
542542
except BaseException as e:
543-
if safe is True:
543+
if safe is True or pinfo.get('safe', True):
544544
jm_log('plugin.exception', e)
545545
else:
546546
raise e

src/jmcomic/jm_plugin.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def build(cls, option: JmOption) -> 'JmOptionPlugin':
3636
return cls(option)
3737

3838
def log(self, msg, topic=None):
39-
if self.log_enable is not True:
39+
if self.log_enable:
4040
return
4141

4242
jm_log(
@@ -68,7 +68,7 @@ def execute_deletion(self, paths: List[str]):
6868
删除文件和文件夹
6969
:param paths: 路径列表
7070
"""
71-
if self.delete_original_file is not True:
71+
if not self.delete_original_file:
7272
return
7373

7474
for p in paths:
@@ -120,7 +120,11 @@ def decide_filepath(self,
120120
参数 dir_rule_dict 优先级最高,
121121
如果 dir_rule_dict 不为空,优先用 dir_rule_dict
122122
否则使用 base_dir + filename_rule + suffix
123+
124+
当album为空时,自动复制为photo.from_album,防止底层dir_rule的dsl包含Axx报错
123125
"""
126+
if album is None:
127+
album = photo.from_album
124128
filepath: str
125129
base_dir: str
126130
if dir_rule_dict is not None:
@@ -248,7 +252,7 @@ def warning():
248252
])
249253
self.log(msg, topic='log')
250254

251-
if enable_warning is True:
255+
if enable_warning:
252256
# 警告
253257
warning()
254258

@@ -776,7 +780,10 @@ def invoke(self,
776780
pdf_filepath = self.decide_filepath(album, photo, filename_rule, 'pdf', pdf_dir, dir_rule)
777781

778782
# 调用 img2pdf 把 photo_dir 下的所有图片转为pdf
779-
img_path_ls, img_dir_ls = self.write_img_2_pdf(pdf_filepath, album, photo, encrypt)
783+
result = self.write_img_2_pdf(pdf_filepath, album, photo, encrypt)
784+
if not result:
785+
return
786+
img_path_ls, img_dir_ls = result
780787
self.log(f'Convert Successfully: JM{album or photo}{pdf_filepath}')
781788

782789
# 执行删除
@@ -801,6 +808,7 @@ def write_img_2_pdf(self, pdf_filepath, album: JmAlbumDetail, photo: JmPhotoDeta
801808

802809
if len(img_path_ls) == 0:
803810
self.log(f'所有文件夹都不存在图片,无法生成pdf:{img_dir_ls}', 'error')
811+
return
804812

805813
with open(pdf_filepath, 'wb') as f:
806814
f.write(img2pdf.convert(img_path_ls))
@@ -851,12 +859,14 @@ def invoke(self,
851859

852860
# 调用 PIL 把 photo_dir 下的所有图片合并为长图
853861
img_path_ls = self.write_img_2_long_img(long_img_path, album, photo)
862+
if not img_path_ls:
863+
return
854864
self.log(f'Convert Successfully: JM{album or photo}{long_img_path}')
855865

856866
# 执行删除
857867
self.execute_deletion(img_path_ls)
858868

859-
def write_img_2_long_img(self, long_img_path, album: JmAlbumDetail, photo: JmPhotoDetail) -> List[str]:
869+
def write_img_2_long_img(self, long_img_path, album: JmAlbumDetail, photo: JmPhotoDetail) -> Optional[List[str]]:
860870
import itertools
861871
from PIL import Image
862872

@@ -868,6 +878,10 @@ def write_img_2_long_img(self, long_img_path, album: JmAlbumDetail, photo: JmPho
868878
img_paths = itertools.chain(*map(files_of_dir, img_dir_items))
869879
img_paths = list(filter(lambda x: not x.startswith('.'), img_paths)) # 过滤系统文件
870880

881+
if not img_paths:
882+
self.log(f'所有文件夹都不存在图片,无法生成long_img:{img_paths}', 'error')
883+
return
884+
871885
images = self.open_images(img_paths)
872886

873887
try:
@@ -954,11 +968,11 @@ def invoke(self,
954968
base_run_kwargs.update(run)
955969
run = base_run_kwargs
956970

957-
if self.running is True:
971+
if self.running:
958972
return
959973

960974
with self.run_server_lock:
961-
if self.running is True:
975+
if self.running:
962976
return
963977

964978
# 服务器的代码位于一个独立库:plugin_jm_server,需要独立安装
@@ -1074,7 +1088,7 @@ def invoke(self,
10741088
self.log('Exception happened: ' + str(e), 'check_update.error')
10751089
continue
10761090

1077-
if has_update is False:
1091+
if not has_update:
10781092
continue
10791093

10801094
self.log(f'album={album_id},发现新章节: {photo_new_list},准备开始下载')

tests/test_jmcomic/test_jm_custom.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ def pname(self):
3636
os.path.abspath(save_dir),
3737
os.path.abspath(base_dir + dic[1] + '/' + dic[2]),
3838
)
39+
JmModuleConfig.CLASS_ALBUM = JmAlbumDetail
40+
JmModuleConfig.CLASS_PHOTO = JmPhotoDetail
3941

4042
def test_extends_api_client(self):
4143
class MyClient(JmApiClient):
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from test_jmcomic import *
2+
3+
4+
class Test_Plugin(JmTestConfigurable):
5+
6+
def test_plugin_missing_album_context(self):
7+
"""
8+
source: https://github.com/hect0x7/JMComic-Crawler-Python/issues/523
9+
10+
测试当仅下载单章(photo)时,如果上下文中缺少 album 对象,
11+
各个包含路径生成的插件(如 download_cover, img2pdf, long_img, zip)
12+
是否能正确从 photo.from_album 中提取专辑属性,
13+
避免解析需要 {Atitle} 等本子级占位符时报错 KeyError。
14+
"""
15+
photo_id = '350234'
16+
option = self.new_option()
17+
18+
flawed_rule = {
19+
'base_dir': option.dir_rule.base_dir,
20+
'rule': '{Atitle}/{Aid}_photo.jpg'
21+
}
22+
23+
from jmcomic.jm_downloader import DoNotDownloadImage
24+
25+
# 将四个需要校验的插件全部进行孤立测试,避免前一个插件后续报错导致循环终端
26+
test_plugins = ['download_cover', 'img2pdf', 'long_img', 'zip']
27+
option.plugins['before_photo'] = [
28+
{
29+
'plugin': plugin_key,
30+
'kwargs': {'dir_rule': flawed_rule},
31+
'safe': False # 防止内部catch异常
32+
}
33+
for plugin_key in test_plugins
34+
]
35+
36+
download_photo(photo_id, option, downloader=DoNotDownloadImage)
37+
print('✅ All folder rule plugins assert completed safely without KeyError.')

0 commit comments

Comments
 (0)