diff --git a/assets/docs/sources/option_file_syntax.md b/assets/docs/sources/option_file_syntax.md index 01b3abd..ea4c987 100644 --- a/assets/docs/sources/option_file_syntax.md +++ b/assets/docs/sources/option_file_syntax.md @@ -96,7 +96,14 @@ dir_rule: # 写法: # 1. 以'Bd'开头,表示根目录 # 2. 文件夹每增加一层,使用 '_' 或者 '/' 区隔 - # 3. 用Pxxx或者Ayyy指代文件夹名,意思是 JmPhotoDetail.xxx / JmAlbumDetail的.yyy。xxx和yyy可以写什么需要看源码。 + # 3. 用Pxxx或者Ayyy指代文件夹名,意思是 JmPhotoDetail.xxx / JmAlbumDetail的.yyy。 + # xxx和yyy可以写什么需要看源码,或通过下面代码打印出所有可用的值 + # + # ```python + # import jmcomic + # properties: dict = jmcomic.JmOption.default().new_jm_client().get_album_detail(本子id).get_properties_dict() + # print(properties) + # ``` # # 下面演示如果要使用禁漫网站的默认下载方式,该怎么写: # 规则: 根目录 / 本子id / 章节序号 / 图片文件 @@ -105,6 +112,9 @@ dir_rule: # 默认规则是: 根目录 / 章节标题 / 图片文件 rule: Bd_Ptitle + # jmcomic v2.5.36 以后,支持使用python的f-string的语法组合文件夹名,下为示例 + # rule: Bd / Aauthor / (JM{Aid}-{Pindex})-{Pname} + # {}大括号里的内容同样是写 Axxx 或 Pxxx,其他语法自行参考python f-string的语法 ``` ## 3. option插件配置项 diff --git a/src/jmcomic/__init__.py b/src/jmcomic/__init__.py index df2750c..5f99c0b 100644 --- a/src/jmcomic/__init__.py +++ b/src/jmcomic/__init__.py @@ -2,7 +2,7 @@ # 被依赖方 <--- 使用方 # config <--- entity <--- toolkit <--- client <--- option <--- downloader -__version__ = '2.5.35' +__version__ = '2.5.36' from .api import * from .jm_plugin import * diff --git a/src/jmcomic/jm_client_interface.py b/src/jmcomic/jm_client_interface.py index 5ec98ea..f522694 100644 --- a/src/jmcomic/jm_client_interface.py +++ b/src/jmcomic/jm_client_interface.py @@ -62,13 +62,16 @@ class JmImageResp(JmResp): img_url=None, ): img_url = img_url or self.url + index = img_url.find("?") + if index != -1: + img_url = img_url[0:index] if decode_image is False or scramble_id is None: # 不解密图片,直接保存文件 JmImageTool.save_resp_img( self, path, - need_convert=suffix_not_equal(img_url[:img_url.find("?")], path), + need_convert=suffix_not_equal(img_url, path), ) else: # 解密图片并保存文件 diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index b920a18..44cd464 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -414,7 +414,7 @@ class JmModuleConfig: 'cache': None, # see CacheRegistry 'domain': [], 'postman': { - 'type': 'cffi', + 'type': 'curl_cffi', 'meta_data': { 'impersonate': 'chrome110', 'headers': None, diff --git a/src/jmcomic/jm_entity.py b/src/jmcomic/jm_entity.py index 4d799b8..ed1d0fb 100644 --- a/src/jmcomic/jm_entity.py +++ b/src/jmcomic/jm_entity.py @@ -164,6 +164,32 @@ class DetailEntity(JmBaseEntity, IndexedEntity): return getattr(detail, ref) + def get_properties_dict(self): + import inspect + + prefix = self.__class__.__name__[2] + result = {} + + # field + for k, v in self.__dict__.items(): + result[prefix + k] = v + + # property + for cls in inspect.getmro(type(self)): + for name, attr in cls.__dict__.items(): + k = prefix + name + if k not in result and isinstance(attr, property): + v = attr.__get__(self, cls) + result[k] = v + + # advice + advice_dict = JmModuleConfig.AFIELD_ADVICE if self.is_album() else JmModuleConfig.PFIELD_ADVICE + for name, func in advice_dict.items(): + k = prefix + name + result[k] = func(self) + + return result + class JmImageDetail(JmBaseEntity, Downloadable): diff --git a/src/jmcomic/jm_option.py b/src/jmcomic/jm_option.py index 79168c3..6c497c1 100644 --- a/src/jmcomic/jm_option.py +++ b/src/jmcomic/jm_option.py @@ -71,7 +71,7 @@ class DirRule: ] Detail = Union[JmAlbumDetail, JmPhotoDetail, None] - RuleFunc = Callable[[Detail], str] + RuleFunc = Callable RuleSolver = Tuple[str, RuleFunc, str] RuleSolverList = List[RuleSolver] @@ -154,6 +154,12 @@ class DirRule: @classmethod def get_rule_solver(cls, rule: str) -> Optional[RuleSolver]: + if '{' in rule: + def format_path(album, photo): + return fix_windir_name(rule.format(**album.get_properties_dict(), **photo.get_properties_dict())).strip() + + return 'F', format_path, rule + # 检查dsl if not rule.startswith(('A', 'P')): return None @@ -176,15 +182,17 @@ class DirRule: def choose_detail(key): if key == 'Bd': - return None + return None, if key == 'A': - return album + return album, if key == 'P': - return photo + return photo, + if key == 'F': + return album, photo key, func, _ = rule_solver detail = choose_detail(key) - return func(detail) + return func(*detail) @classmethod def apply_rule_directly(cls, album, photo, rule: str) -> str: diff --git a/tests/test_jmcomic/test_jm_api.py b/tests/test_jmcomic/test_jm_api.py index ef40118..c2905e2 100644 --- a/tests/test_jmcomic/test_jm_api.py +++ b/tests/test_jmcomic/test_jm_api.py @@ -79,6 +79,13 @@ class Test_Api(JmTestConfigurable): def test_partial_exception(self): class TestDownloader(JmDownloader): + def do_filter(self, detail: DetailEntity): + if detail.is_photo(): + return detail[0:2] + if detail.is_album(): + return detail[0:2] + return super().do_filter(detail) + @catch_exception def download_by_image_detail(self, image: JmImageDetail): raise Exception('test_partial_exception')