jmcomic 2.5.35__py3-none-any.whl → 2.5.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jmcomic/__init__.py +1 -1
- jmcomic/jm_client_interface.py +4 -1
- jmcomic/jm_config.py +1 -1
- jmcomic/jm_entity.py +26 -0
- jmcomic/jm_option.py +52 -78
- jmcomic/jm_plugin.py +1 -1
- {jmcomic-2.5.35.dist-info → jmcomic-2.5.37.dist-info}/METADATA +1 -1
- jmcomic-2.5.37.dist-info/RECORD +18 -0
- {jmcomic-2.5.35.dist-info → jmcomic-2.5.37.dist-info}/WHEEL +1 -1
- jmcomic-2.5.35.dist-info/RECORD +0 -18
- {jmcomic-2.5.35.dist-info → jmcomic-2.5.37.dist-info}/entry_points.txt +0 -0
- {jmcomic-2.5.35.dist-info → jmcomic-2.5.37.dist-info}/licenses/LICENSE +0 -0
- {jmcomic-2.5.35.dist-info → jmcomic-2.5.37.dist-info}/top_level.txt +0 -0
jmcomic/__init__.py
CHANGED
jmcomic/jm_client_interface.py
CHANGED
|
@@ -62,13 +62,16 @@ class JmImageResp(JmResp):
|
|
|
62
62
|
img_url=None,
|
|
63
63
|
):
|
|
64
64
|
img_url = img_url or self.url
|
|
65
|
+
index = img_url.find("?")
|
|
66
|
+
if index != -1:
|
|
67
|
+
img_url = img_url[0:index]
|
|
65
68
|
|
|
66
69
|
if decode_image is False or scramble_id is None:
|
|
67
70
|
# 不解密图片,直接保存文件
|
|
68
71
|
JmImageTool.save_resp_img(
|
|
69
72
|
self,
|
|
70
73
|
path,
|
|
71
|
-
need_convert=suffix_not_equal(img_url
|
|
74
|
+
need_convert=suffix_not_equal(img_url, path),
|
|
72
75
|
)
|
|
73
76
|
else:
|
|
74
77
|
# 解密图片并保存文件
|
jmcomic/jm_config.py
CHANGED
jmcomic/jm_entity.py
CHANGED
|
@@ -164,6 +164,32 @@ class DetailEntity(JmBaseEntity, IndexedEntity):
|
|
|
164
164
|
|
|
165
165
|
return getattr(detail, ref)
|
|
166
166
|
|
|
167
|
+
def get_properties_dict(self):
|
|
168
|
+
import inspect
|
|
169
|
+
|
|
170
|
+
prefix = self.__class__.__name__[2]
|
|
171
|
+
result = {}
|
|
172
|
+
|
|
173
|
+
# field
|
|
174
|
+
for k, v in self.__dict__.items():
|
|
175
|
+
result[prefix + k] = v
|
|
176
|
+
|
|
177
|
+
# property
|
|
178
|
+
for cls in inspect.getmro(type(self)):
|
|
179
|
+
for name, attr in cls.__dict__.items():
|
|
180
|
+
k = prefix + name
|
|
181
|
+
if k not in result and isinstance(attr, property):
|
|
182
|
+
v = attr.__get__(self, cls)
|
|
183
|
+
result[k] = v
|
|
184
|
+
|
|
185
|
+
# advice
|
|
186
|
+
advice_dict = JmModuleConfig.AFIELD_ADVICE if self.is_album() else JmModuleConfig.PFIELD_ADVICE
|
|
187
|
+
for name, func in advice_dict.items():
|
|
188
|
+
k = prefix + name
|
|
189
|
+
result[k] = func(self)
|
|
190
|
+
|
|
191
|
+
return result
|
|
192
|
+
|
|
167
193
|
|
|
168
194
|
class JmImageDetail(JmBaseEntity, Downloadable):
|
|
169
195
|
|
jmcomic/jm_option.py
CHANGED
|
@@ -58,90 +58,85 @@ class CacheRegistry:
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class DirRule:
|
|
61
|
-
|
|
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[[Detail], str]
|
|
75
|
-
RuleSolver = Tuple[str, RuleFunc, str]
|
|
76
|
-
RuleSolverList = List[RuleSolver]
|
|
61
|
+
RULE_BASE_DIR = 'Bd'
|
|
77
62
|
|
|
78
63
|
def __init__(self, rule: str, base_dir=None):
|
|
79
64
|
base_dir = JmcomicText.parse_to_abspath(base_dir)
|
|
80
65
|
self.base_dir = base_dir
|
|
81
66
|
self.rule_dsl = rule
|
|
82
|
-
self.
|
|
67
|
+
self.parser_list: List[Tuple[str, Callable]] = self.get_rule_parser_list(rule)
|
|
83
68
|
|
|
84
69
|
def decide_image_save_dir(self,
|
|
85
70
|
album: JmAlbumDetail,
|
|
86
71
|
photo: JmPhotoDetail,
|
|
87
72
|
) -> str:
|
|
88
|
-
|
|
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)
|
|
100
74
|
|
|
101
75
|
def decide_album_root_dir(self, album: JmAlbumDetail) -> str:
|
|
102
|
-
|
|
103
|
-
for solver in self.solver_list:
|
|
104
|
-
key, _, rule = solver
|
|
76
|
+
return self._build_path_from_rules(album, None, True)
|
|
105
77
|
|
|
106
|
-
|
|
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')):
|
|
107
82
|
continue
|
|
108
83
|
|
|
109
84
|
try:
|
|
110
|
-
|
|
85
|
+
path = parser(album, photo, rule)
|
|
111
86
|
except BaseException as e:
|
|
112
87
|
# noinspection PyUnboundLocalVariable
|
|
113
|
-
jm_log('dir_rule', f'路径规则"{rule}"的解析出错: {e}, album={album}')
|
|
88
|
+
jm_log('dir_rule', f'路径规则"{rule}"的解析出错: {e}, album={album}, photo={photo}')
|
|
114
89
|
raise e
|
|
90
|
+
if parser != self.parse_bd_rule:
|
|
91
|
+
path = fix_windir_name(str(path)).strip()
|
|
115
92
|
|
|
116
|
-
path_ls.append(
|
|
93
|
+
path_ls.append(path)
|
|
117
94
|
|
|
118
95
|
return fix_filepath('/'.join(path_ls), is_dir=True)
|
|
119
96
|
|
|
120
|
-
def
|
|
97
|
+
def get_rule_parser_list(self, rule_dsl: str):
|
|
121
98
|
"""
|
|
122
99
|
解析下载路径dsl,得到一个路径规则解析列表
|
|
123
100
|
"""
|
|
124
101
|
|
|
125
102
|
rule_list = self.split_rule_dsl(rule_dsl)
|
|
126
|
-
|
|
103
|
+
parser_list: list = []
|
|
127
104
|
|
|
128
105
|
for rule in rule_list:
|
|
129
106
|
rule = rule.strip()
|
|
130
|
-
if rule ==
|
|
131
|
-
|
|
107
|
+
if rule == self.RULE_BASE_DIR:
|
|
108
|
+
parser_list.append((rule, self.parse_bd_rule))
|
|
132
109
|
continue
|
|
133
110
|
|
|
134
|
-
|
|
135
|
-
if
|
|
111
|
+
parser = self.get_rule_parser(rule)
|
|
112
|
+
if parser is None:
|
|
136
113
|
ExceptionTool.raises(f'不支持的dsl: "{rule}" in "{rule_dsl}"')
|
|
137
114
|
|
|
138
|
-
|
|
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)
|
|
139
131
|
|
|
140
|
-
|
|
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:]))
|
|
141
136
|
|
|
142
137
|
# noinspection PyMethodMayBeStatic
|
|
143
|
-
def split_rule_dsl(self, rule_dsl: str)
|
|
144
|
-
if rule_dsl ==
|
|
138
|
+
def split_rule_dsl(self, rule_dsl: str):
|
|
139
|
+
if rule_dsl == self.RULE_BASE_DIR:
|
|
145
140
|
return [rule_dsl]
|
|
146
141
|
|
|
147
142
|
if '/' in rule_dsl:
|
|
@@ -153,42 +148,21 @@ class DirRule:
|
|
|
153
148
|
ExceptionTool.raises(f'不支持的rule配置: "{rule_dsl}"')
|
|
154
149
|
|
|
155
150
|
@classmethod
|
|
156
|
-
def
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return None
|
|
160
|
-
|
|
161
|
-
def solve_func(detail):
|
|
162
|
-
return fix_windir_name(str(DetailEntity.get_dirname(detail, rule[1:]))).strip()
|
|
163
|
-
|
|
164
|
-
return rule[0], solve_func, rule
|
|
165
|
-
|
|
166
|
-
@classmethod
|
|
167
|
-
def apply_rule_solver(cls, album, photo, rule_solver: RuleSolver) -> str:
|
|
168
|
-
"""
|
|
169
|
-
应用规则解析器(RuleSolver)
|
|
151
|
+
def get_rule_parser(cls, rule: str):
|
|
152
|
+
if '{' in rule:
|
|
153
|
+
return cls.parse_f_string_rule
|
|
170
154
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
:param rule_solver: Ptitle
|
|
174
|
-
:returns: photo.title
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
def choose_detail(key):
|
|
178
|
-
if key == 'Bd':
|
|
179
|
-
return None
|
|
180
|
-
if key == 'A':
|
|
181
|
-
return album
|
|
182
|
-
if key == 'P':
|
|
183
|
-
return photo
|
|
155
|
+
if rule.startswith(('A', 'P')):
|
|
156
|
+
return cls.parse_detail_rule
|
|
184
157
|
|
|
185
|
-
|
|
186
|
-
detail = choose_detail(key)
|
|
187
|
-
return func(detail)
|
|
158
|
+
ExceptionTool.raises(f'不支持的rule配置: "{rule}"')
|
|
188
159
|
|
|
189
160
|
@classmethod
|
|
190
161
|
def apply_rule_directly(cls, album, photo, rule: str) -> str:
|
|
191
|
-
|
|
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()
|
|
192
166
|
|
|
193
167
|
|
|
194
168
|
class JmOption:
|
|
@@ -463,7 +437,7 @@ class JmOption:
|
|
|
463
437
|
orig_cookies.update(cookies)
|
|
464
438
|
metadata['cookies'] = orig_cookies
|
|
465
439
|
|
|
466
|
-
# noinspection PyMethodMayBeStatic
|
|
440
|
+
# noinspection PyMethodMayBeStatic,PyTypeChecker
|
|
467
441
|
def decide_client_domain(self, client_key: str) -> List[str]:
|
|
468
442
|
def is_client_type(ctype) -> bool:
|
|
469
443
|
return self.client_key_is_given_type(client_key, ctype)
|
jmcomic/jm_plugin.py
CHANGED
|
@@ -307,7 +307,7 @@ class ZipPlugin(JmOptionPlugin):
|
|
|
307
307
|
|
|
308
308
|
elif level == 'photo':
|
|
309
309
|
for photo, image_list in photo_dict.items():
|
|
310
|
-
zip_path = self.get_zip_path(
|
|
310
|
+
zip_path = self.get_zip_path(photo.from_album, photo, filename_rule, suffix, zip_dir)
|
|
311
311
|
self.zip_photo(photo, image_list, zip_path, path_to_delete)
|
|
312
312
|
|
|
313
313
|
else:
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
jmcomic/__init__.py,sha256=PoBTwaWIz9PGFi2pFAB2WlKz7bj_5r7ltJFoAZvmCu8,903
|
|
2
|
+
jmcomic/api.py,sha256=ZduhXDmh4lg1dkXHs7UTAaPpYNO7kcdPCDH5JJT9KSI,4253
|
|
3
|
+
jmcomic/cl.py,sha256=PBSh0JndNFZw3B7WJPj5Y8SeFdKzHE00jIwYo9An-K0,3475
|
|
4
|
+
jmcomic/jm_client_impl.py,sha256=m8-e_TA3vIXdUkXJcuJ0uzek4GM48y4QvBRXrT6JqUc,39633
|
|
5
|
+
jmcomic/jm_client_interface.py,sha256=Bld80cYwBwIqcMSJK09g5q8U_UX3IWnQJxuRJQwmIOk,19082
|
|
6
|
+
jmcomic/jm_config.py,sha256=p7g2FQMVXBnejz1sSzM15YAtJ5f91fZZeNMqFeYum5I,16772
|
|
7
|
+
jmcomic/jm_downloader.py,sha256=6w9D7eoL2M85-ScH745-OZBvaC0uwGkHi6awTUzq-3E,11036
|
|
8
|
+
jmcomic/jm_entity.py,sha256=x-3yUvM74C_Gof20mJw2SmZq7sSSsGNg0Cp47oZ-dFg,19968
|
|
9
|
+
jmcomic/jm_exception.py,sha256=x3KGMLlQS2zi1GX7z5G58zJN2EwLkI4mAURkxZYjEvA,5055
|
|
10
|
+
jmcomic/jm_option.py,sha256=6hwnm4UPnQPujsA3Gkt17krnJfUF435b-272hVLqlTk,21167
|
|
11
|
+
jmcomic/jm_plugin.py,sha256=1sSPbo2ieXW-asmXapJ0ZaB1Lx5co7SS5dfbYchJ1X4,39914
|
|
12
|
+
jmcomic/jm_toolkit.py,sha256=_qAJKbcV9jaFHRGvGU4Na2ts5h7QPGJS4uRQ05KpQ88,29166
|
|
13
|
+
jmcomic-2.5.37.dist-info/licenses/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
14
|
+
jmcomic-2.5.37.dist-info/METADATA,sha256=hovvk8BXYGUUPaMUnqRPIQWPyFEeOkuPnGYkg3nfsMY,8161
|
|
15
|
+
jmcomic-2.5.37.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
|
16
|
+
jmcomic-2.5.37.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
|
|
17
|
+
jmcomic-2.5.37.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
18
|
+
jmcomic-2.5.37.dist-info/RECORD,,
|
jmcomic-2.5.35.dist-info/RECORD
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
jmcomic/__init__.py,sha256=5Qyc6r1XhjnQJsvyr2bhgqDvxd0lAr-6U4SeOzAlyAs,903
|
|
2
|
-
jmcomic/api.py,sha256=ZduhXDmh4lg1dkXHs7UTAaPpYNO7kcdPCDH5JJT9KSI,4253
|
|
3
|
-
jmcomic/cl.py,sha256=PBSh0JndNFZw3B7WJPj5Y8SeFdKzHE00jIwYo9An-K0,3475
|
|
4
|
-
jmcomic/jm_client_impl.py,sha256=m8-e_TA3vIXdUkXJcuJ0uzek4GM48y4QvBRXrT6JqUc,39633
|
|
5
|
-
jmcomic/jm_client_interface.py,sha256=LqJqa-4G7-F98_U9R9QTxFND_9t30B-BIQZa_o0p-KY,19005
|
|
6
|
-
jmcomic/jm_config.py,sha256=rOeKMqZ3HwWk3I-vA0YTCIimBcfdZpvXj7Itg0OKfCo,16767
|
|
7
|
-
jmcomic/jm_downloader.py,sha256=6w9D7eoL2M85-ScH745-OZBvaC0uwGkHi6awTUzq-3E,11036
|
|
8
|
-
jmcomic/jm_entity.py,sha256=vz_nZbEtRLBRrVz97533Twf9mxB1AlwauunCvdhFa7w,19190
|
|
9
|
-
jmcomic/jm_exception.py,sha256=x3KGMLlQS2zi1GX7z5G58zJN2EwLkI4mAURkxZYjEvA,5055
|
|
10
|
-
jmcomic/jm_option.py,sha256=2tINFsDcncCJbd6FRtCMAidhro6faB8TBLoaSxP3uQ8,21926
|
|
11
|
-
jmcomic/jm_plugin.py,sha256=e2B_x2adghxn7f8eKAJivDWf8oLY9962Utt1-J70zBw,39902
|
|
12
|
-
jmcomic/jm_toolkit.py,sha256=_qAJKbcV9jaFHRGvGU4Na2ts5h7QPGJS4uRQ05KpQ88,29166
|
|
13
|
-
jmcomic-2.5.35.dist-info/licenses/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
14
|
-
jmcomic-2.5.35.dist-info/METADATA,sha256=urkZ5ZX0yGsUOhLpc8yY-LGwwMZPAu9rcQTN8cAwbtc,8161
|
|
15
|
-
jmcomic-2.5.35.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
16
|
-
jmcomic-2.5.35.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
|
|
17
|
-
jmcomic-2.5.35.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
18
|
-
jmcomic-2.5.35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|