Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ psutil
pycryptodome
requests
plugin_jm_server
zhconv
zhconv
img2pdf
2 changes: 1 addition & 1 deletion src/jmcomic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# 被依赖方 <--- 使用方
# config <--- entity <--- toolkit <--- client <--- option <--- downloader

__version__ = '2.6.16'
__version__ = '2.6.17'

from .api import *
from .jm_plugin import *
Expand Down
8 changes: 4 additions & 4 deletions src/jmcomic/jm_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class JmMagicConstants:
APP_TOKEN_SECRET_2 = '18comicAPPContent'
APP_DATA_SECRET = '185Hcomic3PAPP7R'
API_DOMAIN_SERVER_SECRET = 'diosfjckwpqpdfjkvnqQjsik'
APP_VERSION = '2.0.18'
APP_VERSION = '2.0.19'


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

@classmethod
def jm_log(cls, topic: str, msg: str, e: Exception = None):
if cls.FLAG_ENABLE_JM_LOG is True:
def jm_log(cls, topic: str, msg, e: Exception = None):
if cls.FLAG_ENABLE_JM_LOG:
executor = cls.EXECUTOR_LOG
if e is None:
executor(topic, msg)
Expand Down Expand Up @@ -440,7 +440,7 @@ def new_postman(cls, session=False, **kwargs):

from common import Postmans

if session is True:
if session:
return Postmans.new_session(**kwargs)

return Postmans.new_postman(**kwargs)
Expand Down
4 changes: 2 additions & 2 deletions src/jmcomic/jm_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ def download_photo(self,

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

def call_all_plugin(self, group: str, safe=True, **extra):
def call_all_plugin(self, group: str, safe=None, **extra):
plugin_list: List[dict] = self.plugins.get(group, [])
if plugin_list is None or len(plugin_list) == 0:
return
Expand All @@ -540,7 +540,7 @@ def call_all_plugin(self, group: str, safe=True, **extra):
try:
self.invoke_plugin(pclass, kwargs, extra, pinfo)
except BaseException as e:
if safe is True:
if safe is True or pinfo.get('safe', True):
jm_log('plugin.exception', e)
else:
raise e
Expand Down
30 changes: 22 additions & 8 deletions src/jmcomic/jm_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def build(cls, option: JmOption) -> 'JmOptionPlugin':
return cls(option)

def log(self, msg, topic=None):
if self.log_enable is not True:
if self.log_enable:
return

jm_log(
Expand Down Expand Up @@ -68,7 +68,7 @@ def execute_deletion(self, paths: List[str]):
删除文件和文件夹
:param paths: 路径列表
"""
if self.delete_original_file is not True:
if not self.delete_original_file:
return

for p in paths:
Expand Down Expand Up @@ -120,7 +120,11 @@ def decide_filepath(self,
参数 dir_rule_dict 优先级最高,
如果 dir_rule_dict 不为空,优先用 dir_rule_dict
否则使用 base_dir + filename_rule + suffix

当album为空时,自动复制为photo.from_album,防止底层dir_rule的dsl包含Axx报错
"""
if album is None:
album = photo.from_album
Comment thread
hect0x7 marked this conversation as resolved.
filepath: str
base_dir: str
if dir_rule_dict is not None:
Expand Down Expand Up @@ -248,7 +252,7 @@ def warning():
])
self.log(msg, topic='log')

if enable_warning is True:
if enable_warning:
# 警告
warning()

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

# 调用 img2pdf 把 photo_dir 下的所有图片转为pdf
img_path_ls, img_dir_ls = self.write_img_2_pdf(pdf_filepath, album, photo, encrypt)
result = self.write_img_2_pdf(pdf_filepath, album, photo, encrypt)
if not result:
return
img_path_ls, img_dir_ls = result
self.log(f'Convert Successfully: JM{album or photo} → {pdf_filepath}')

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

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

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

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

# 执行删除
self.execute_deletion(img_path_ls)

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

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

if not img_paths:
self.log(f'所有文件夹都不存在图片,无法生成long_img:{img_paths}', 'error')
return

images = self.open_images(img_paths)

try:
Expand Down Expand Up @@ -954,11 +968,11 @@ def invoke(self,
base_run_kwargs.update(run)
run = base_run_kwargs

if self.running is True:
if self.running:
return

with self.run_server_lock:
if self.running is True:
if self.running:
return

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

if has_update is False:
if not has_update:
continue

self.log(f'album={album_id},发现新章节: {photo_new_list},准备开始下载')
Expand Down
2 changes: 2 additions & 0 deletions tests/test_jmcomic/test_jm_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def pname(self):
os.path.abspath(save_dir),
os.path.abspath(base_dir + dic[1] + '/' + dic[2]),
)
JmModuleConfig.CLASS_ALBUM = JmAlbumDetail
JmModuleConfig.CLASS_PHOTO = JmPhotoDetail

def test_extends_api_client(self):
class MyClient(JmApiClient):
Expand Down
37 changes: 37 additions & 0 deletions tests/test_jmcomic/test_jm_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from test_jmcomic import *


class Test_Plugin(JmTestConfigurable):

def test_plugin_missing_album_context(self):
"""
source: https://github.com/hect0x7/JMComic-Crawler-Python/issues/523

测试当仅下载单章(photo)时,如果上下文中缺少 album 对象,
各个包含路径生成的插件(如 download_cover, img2pdf, long_img, zip)
是否能正确从 photo.from_album 中提取专辑属性,
避免解析需要 {Atitle} 等本子级占位符时报错 KeyError。
"""
photo_id = '350234'
option = self.new_option()

flawed_rule = {
'base_dir': option.dir_rule.base_dir,
'rule': '{Atitle}/{Aid}_photo.jpg'
}

from jmcomic.jm_downloader import DoNotDownloadImage

# 将四个需要校验的插件全部进行孤立测试,避免前一个插件后续报错导致循环终端
test_plugins = ['download_cover', 'img2pdf', 'long_img', 'zip']
option.plugins['before_photo'] = [
{
'plugin': plugin_key,
'kwargs': {'dir_rule': flawed_rule},
'safe': False # 防止内部catch异常
}
for plugin_key in test_plugins
]

download_photo(photo_id, option, downloader=DoNotDownloadImage)
Comment thread
hect0x7 marked this conversation as resolved.
print('✅ All folder rule plugins assert completed safely without KeyError.')