Skip to content

Commit 544c6aa

Browse files
authored
v2.5.37: 插件filename_rule配置项支持f-string语法 (#426)
1 parent 398e1ea commit 544c6aa

File tree

3 files changed

+53
-87
lines changed

3 files changed

+53
-87
lines changed

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.36'
5+
__version__ = '2.5.37'
66

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

src/jmcomic/jm_option.py

Lines changed: 51 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -58,90 +58,85 @@ def enable_client_cache_on_condition(cls,
5858

5959

6060
class DirRule:
61-
rule_sample = [
62-
# 根目录 / Album-id / Photo-序号 /
63-
'Bd_Aid_Pindex', # 禁漫网站的默认下载方式
64-
# 根目录 / Album-作者 / Album-标题 / Photo-序号 /
65-
'Bd_Aauthor_Atitle_Pindex',
66-
# 根目录 / Photo-序号&标题 /
67-
'Bd_Pindextitle',
68-
# 根目录 / Photo-自定义类属性 /
69-
'Bd_Aauthor_Atitle_Pcustomfield',
70-
# 需要替换JmModuleConfig.CLASS_ALBUM / CLASS_PHOTO才能让自定义属性生效
71-
]
72-
73-
Detail = Union[JmAlbumDetail, JmPhotoDetail, None]
74-
RuleFunc = Callable
75-
RuleSolver = Tuple[str, RuleFunc, str]
76-
RuleSolverList = List[RuleSolver]
61+
RULE_BASE_DIR = 'Bd'
7762

7863
def __init__(self, rule: str, base_dir=None):
7964
base_dir = JmcomicText.parse_to_abspath(base_dir)
8065
self.base_dir = base_dir
8166
self.rule_dsl = rule
82-
self.solver_list = self.get_role_solver_list(rule, base_dir)
67+
self.parser_list: List[Tuple[str, Callable]] = self.get_rule_parser_list(rule)
8368

8469
def decide_image_save_dir(self,
8570
album: JmAlbumDetail,
8671
photo: JmPhotoDetail,
8772
) -> str:
88-
path_ls = []
89-
for solver in self.solver_list:
90-
try:
91-
ret = self.apply_rule_solver(album, photo, solver)
92-
except BaseException as e:
93-
# noinspection PyUnboundLocalVariable
94-
jm_log('dir_rule', f'路径规则"{solver[2]}"的解析出错: {e}, album={album}, photo={photo}')
95-
raise e
96-
97-
path_ls.append(str(ret))
98-
99-
return fix_filepath('/'.join(path_ls), is_dir=True)
73+
return self._build_path_from_rules(album, photo)
10074

10175
def decide_album_root_dir(self, album: JmAlbumDetail) -> str:
102-
path_ls = []
103-
for solver in self.solver_list:
104-
key, _, rule = solver
76+
return self._build_path_from_rules(album, None, True)
10577

106-
if key != 'Bd' and key != 'A':
78+
def _build_path_from_rules(self, album, photo, only_album_rules=False) -> str:
79+
path_ls = []
80+
for rule, parser in self.parser_list:
81+
if only_album_rules and not (rule == self.RULE_BASE_DIR or rule.startswith('A')):
10782
continue
10883

10984
try:
110-
ret = self.apply_rule_solver(album, None, solver)
85+
path = parser(album, photo, rule)
11186
except BaseException as e:
11287
# noinspection PyUnboundLocalVariable
113-
jm_log('dir_rule', f'路径规则"{rule}"的解析出错: {e}, album={album}')
88+
jm_log('dir_rule', f'路径规则"{rule}"的解析出错: {e}, album={album}, photo={photo}')
11489
raise e
90+
if parser != self.parse_bd_rule:
91+
path = fix_windir_name(str(path)).strip()
11592

116-
path_ls.append(str(ret))
93+
path_ls.append(path)
11794

11895
return fix_filepath('/'.join(path_ls), is_dir=True)
11996

120-
def get_role_solver_list(self, rule_dsl: str, base_dir: str) -> RuleSolverList:
97+
def get_rule_parser_list(self, rule_dsl: str):
12198
"""
12299
解析下载路径dsl,得到一个路径规则解析列表
123100
"""
124101

125102
rule_list = self.split_rule_dsl(rule_dsl)
126-
solver_ls: List[DirRule.RuleSolver] = []
103+
parser_list: list = []
127104

128105
for rule in rule_list:
129106
rule = rule.strip()
130-
if rule == 'Bd':
131-
solver_ls.append(('Bd', lambda _: base_dir, 'Bd'))
107+
if rule == self.RULE_BASE_DIR:
108+
parser_list.append((rule, self.parse_bd_rule))
132109
continue
133110

134-
rule_solver = self.get_rule_solver(rule)
135-
if rule_solver is None:
111+
parser = self.get_rule_parser(rule)
112+
if parser is None:
136113
ExceptionTool.raises(f'不支持的dsl: "{rule}" in "{rule_dsl}"')
137114

138-
solver_ls.append(rule_solver)
115+
parser_list.append((rule, parser))
116+
117+
return parser_list
118+
119+
# noinspection PyUnusedLocal
120+
def parse_bd_rule(self, album, photo, rule):
121+
return self.base_dir
122+
123+
@classmethod
124+
def parse_f_string_rule(cls, album, photo, rule: str):
125+
properties = {}
126+
if album:
127+
properties.update(album.get_properties_dict())
128+
if photo:
129+
properties.update(photo.get_properties_dict())
130+
return rule.format(**properties)
139131

140-
return solver_ls
132+
@classmethod
133+
def parse_detail_rule(cls, album, photo, rule: str):
134+
detail = album if rule.startswith('A') else photo
135+
return str(DetailEntity.get_dirname(detail, rule[1:]))
141136

142137
# noinspection PyMethodMayBeStatic
143-
def split_rule_dsl(self, rule_dsl: str) -> List[str]:
144-
if rule_dsl == 'Bd':
138+
def split_rule_dsl(self, rule_dsl: str):
139+
if rule_dsl == self.RULE_BASE_DIR:
145140
return [rule_dsl]
146141

147142
if '/' in rule_dsl:
@@ -153,50 +148,21 @@ def split_rule_dsl(self, rule_dsl: str) -> List[str]:
153148
ExceptionTool.raises(f'不支持的rule配置: "{rule_dsl}"')
154149

155150
@classmethod
156-
def get_rule_solver(cls, rule: str) -> Optional[RuleSolver]:
151+
def get_rule_parser(cls, rule: str):
157152
if '{' in rule:
158-
def format_path(album, photo):
159-
return fix_windir_name(rule.format(**album.get_properties_dict(), **photo.get_properties_dict())).strip()
160-
161-
return 'F', format_path, rule
153+
return cls.parse_f_string_rule
162154

163-
# 检查dsl
164-
if not rule.startswith(('A', 'P')):
165-
return None
155+
if rule.startswith(('A', 'P')):
156+
return cls.parse_detail_rule
166157

167-
def solve_func(detail):
168-
return fix_windir_name(str(DetailEntity.get_dirname(detail, rule[1:]))).strip()
169-
170-
return rule[0], solve_func, rule
171-
172-
@classmethod
173-
def apply_rule_solver(cls, album, photo, rule_solver: RuleSolver) -> str:
174-
"""
175-
应用规则解析器(RuleSolver)
176-
177-
:param album: JmAlbumDetail
178-
:param photo: JmPhotoDetail
179-
:param rule_solver: Ptitle
180-
:returns: photo.title
181-
"""
182-
183-
def choose_detail(key):
184-
if key == 'Bd':
185-
return None,
186-
if key == 'A':
187-
return album,
188-
if key == 'P':
189-
return photo,
190-
if key == 'F':
191-
return album, photo
192-
193-
key, func, _ = rule_solver
194-
detail = choose_detail(key)
195-
return func(*detail)
158+
ExceptionTool.raises(f'不支持的rule配置: "{rule}"')
196159

197160
@classmethod
198161
def apply_rule_directly(cls, album, photo, rule: str) -> str:
199-
return cls.apply_rule_solver(album, photo, cls.get_rule_solver(rule))
162+
if album is None:
163+
album = photo.from_album
164+
# noinspection PyArgumentList
165+
return fix_windir_name(cls.get_rule_parser(rule)(album, photo, rule)).strip()
200166

201167

202168
class JmOption:
@@ -471,7 +437,7 @@ def update_cookies(self, cookies: dict):
471437
orig_cookies.update(cookies)
472438
metadata['cookies'] = orig_cookies
473439

474-
# noinspection PyMethodMayBeStatic
440+
# noinspection PyMethodMayBeStatic,PyTypeChecker
475441
def decide_client_domain(self, client_key: str) -> List[str]:
476442
def is_client_type(ctype) -> bool:
477443
return self.client_key_is_given_type(client_key, ctype)

src/jmcomic/jm_plugin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def invoke(self,
307307

308308
elif level == 'photo':
309309
for photo, image_list in photo_dict.items():
310-
zip_path = self.get_zip_path(None, photo, filename_rule, suffix, zip_dir)
310+
zip_path = self.get_zip_path(photo.from_album, photo, filename_rule, suffix, zip_dir)
311311
self.zip_photo(photo, image_list, zip_path, path_to_delete)
312312

313313
else:

0 commit comments

Comments
 (0)