jmcomic 2.0.4__tar.gz → 2.0.6__tar.gz
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-2.0.4/src/jmcomic.egg-info → jmcomic-2.0.6}/PKG-INFO +1 -1
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/__init__.py +1 -1
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_client_impl.py +14 -5
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_client_interface.py +6 -2
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_config.py +21 -8
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_entity.py +6 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_option.py +0 -87
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/jm_toolkit.py +0 -2
- {jmcomic-2.0.4 → jmcomic-2.0.6/src/jmcomic.egg-info}/PKG-INFO +1 -1
- {jmcomic-2.0.4 → jmcomic-2.0.6}/LICENSE +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/README.md +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/setup.cfg +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/setup.py +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic/api.py +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic.egg-info/SOURCES.txt +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic.egg-info/dependency_links.txt +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic.egg-info/requires.txt +0 -0
- {jmcomic-2.0.4 → jmcomic-2.0.6}/src/jmcomic.egg-info/top_level.txt +0 -0
|
@@ -95,9 +95,18 @@ class AbstractJmClient(
|
|
|
95
95
|
|
|
96
96
|
setattr(self, func_name, wrap_func)
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
for func in {
|
|
99
|
+
'get_photo_detail',
|
|
100
|
+
'get_album_detail',
|
|
101
|
+
'search_album',
|
|
102
|
+
}:
|
|
103
|
+
wrap_func_cache(func, func + '.cache.dict')
|
|
104
|
+
|
|
105
|
+
def get_jmcomic_url(self, postman=None):
|
|
106
|
+
return JmModuleConfig.get_jmcomic_url(postman or self.get_root_postman())
|
|
107
|
+
|
|
108
|
+
def get_jmcomic_domain_all(self, postman=None):
|
|
109
|
+
return JmModuleConfig.get_jmcomic_domain_all(postman or self.get_root_postman())
|
|
101
110
|
|
|
102
111
|
|
|
103
112
|
# 基于网页实现的JmClient
|
|
@@ -113,7 +122,7 @@ class JmHtmlClient(AbstractJmClient):
|
|
|
113
122
|
# 用 JmcomicText 解析 html,返回实体类
|
|
114
123
|
return JmcomicText.analyse_jm_album_html(resp.text)
|
|
115
124
|
|
|
116
|
-
def get_photo_detail(self, photo_id
|
|
125
|
+
def get_photo_detail(self, photo_id, fetch_album=True) -> JmPhotoDetail:
|
|
117
126
|
# 参数校验
|
|
118
127
|
photo_id = JmcomicText.parse_to_photo_id(photo_id)
|
|
119
128
|
|
|
@@ -124,7 +133,7 @@ class JmHtmlClient(AbstractJmClient):
|
|
|
124
133
|
photo_detail = JmcomicText.analyse_jm_photo_html(resp.text)
|
|
125
134
|
|
|
126
135
|
# 一并获取该章节的所处本子
|
|
127
|
-
if
|
|
136
|
+
if fetch_album is True:
|
|
128
137
|
photo_detail.from_album = self.get_album_detail(photo_detail.album_id)
|
|
129
138
|
|
|
130
139
|
return photo_detail
|
|
@@ -127,7 +127,7 @@ class JmDetailClient:
|
|
|
127
127
|
def get_album_detail(self, album_id) -> JmAlbumDetail:
|
|
128
128
|
raise NotImplementedError
|
|
129
129
|
|
|
130
|
-
def get_photo_detail(self, photo_id
|
|
130
|
+
def get_photo_detail(self, photo_id, fetch_album=True) -> JmPhotoDetail:
|
|
131
131
|
raise NotImplementedError
|
|
132
132
|
|
|
133
133
|
def ensure_photo_can_use(self, photo_detail: JmPhotoDetail):
|
|
@@ -210,4 +210,8 @@ class JmcomicClient(
|
|
|
210
210
|
JmUserClient,
|
|
211
211
|
Postman,
|
|
212
212
|
):
|
|
213
|
-
|
|
213
|
+
def get_jmcomic_url(self, postman=None):
|
|
214
|
+
return JmModuleConfig.get_jmcomic_url(postman or self)
|
|
215
|
+
|
|
216
|
+
def get_jmcomic_domain_all(self, postman=None):
|
|
217
|
+
return JmModuleConfig.get_jmcomic_domain_all(postman or self)
|
|
@@ -3,12 +3,24 @@ def default_jm_debug(topic: str, msg: str):
|
|
|
3
3
|
print(f'{format_ts()}:【{topic}】{msg}')
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
def default_postman_constructor(session, **kwargs):
|
|
7
|
+
from common import Postmans
|
|
8
|
+
|
|
9
|
+
kwargs.setdefault('impersonate', 'chrome110')
|
|
10
|
+
kwargs.setdefault('headers', JmModuleConfig.headers())
|
|
11
|
+
|
|
12
|
+
if session is True:
|
|
13
|
+
return Postmans.new_session(**kwargs)
|
|
14
|
+
|
|
15
|
+
return Postmans.new_postman(**kwargs)
|
|
16
|
+
|
|
17
|
+
|
|
6
18
|
class JmModuleConfig:
|
|
7
19
|
# 网站相关
|
|
8
20
|
PROT = "https://"
|
|
9
21
|
DOMAIN = None
|
|
10
|
-
JM_REDIRECT_URL = f'{PROT}jm365.
|
|
11
|
-
JM_PUB_URL = f'{PROT}
|
|
22
|
+
JM_REDIRECT_URL = f'{PROT}jm365.work/3YeBdF' # 永久網域,怕走失的小伙伴收藏起来
|
|
23
|
+
JM_PUB_URL = f'{PROT}jmcomic2.bet'
|
|
12
24
|
JM_CDN_IMAGE_URL_TEMPLATE = PROT + 'cdn-msp.{domain}/media/photos/{photo_id}/{index:05}{suffix}' # index 从1开始
|
|
13
25
|
JM_IMAGE_SUFFIX = ['.jpg', '.webp', '.png', '.gif']
|
|
14
26
|
|
|
@@ -40,6 +52,7 @@ class JmModuleConfig:
|
|
|
40
52
|
# debug
|
|
41
53
|
enable_jm_debug = True
|
|
42
54
|
debug_executor = default_jm_debug
|
|
55
|
+
postman_constructor = default_postman_constructor
|
|
43
56
|
|
|
44
57
|
@classmethod
|
|
45
58
|
def domain(cls, postman=None):
|
|
@@ -84,15 +97,17 @@ class JmModuleConfig:
|
|
|
84
97
|
def disable_jm_debug(cls):
|
|
85
98
|
cls.enable_jm_debug = False
|
|
86
99
|
|
|
100
|
+
@classmethod
|
|
101
|
+
def new_postman(cls, session=False, **kwargs):
|
|
102
|
+
return cls.postman_constructor(session, **kwargs)
|
|
103
|
+
|
|
87
104
|
@classmethod
|
|
88
105
|
def get_jmcomic_url(cls, postman=None):
|
|
89
106
|
"""
|
|
90
107
|
访问禁漫的永久网域,从而得到一个可用的禁漫网址
|
|
91
108
|
@return: https://jm-comic2.cc
|
|
92
109
|
"""
|
|
93
|
-
|
|
94
|
-
from common import Postmans
|
|
95
|
-
postman = Postmans.get_impl_clazz('cffi_Session').create()
|
|
110
|
+
postman = postman or cls.new_postman(session=True)
|
|
96
111
|
|
|
97
112
|
resp = postman.get(cls.JM_REDIRECT_URL)
|
|
98
113
|
url = resp.url
|
|
@@ -105,9 +120,7 @@ class JmModuleConfig:
|
|
|
105
120
|
访问禁漫发布页,得到所有禁漫的域名
|
|
106
121
|
@return:['18comic.vip', ..., 'jm365.xyz/ZNPJam'], 最后一个是【APP軟件下載】
|
|
107
122
|
"""
|
|
108
|
-
|
|
109
|
-
from common import Postmans
|
|
110
|
-
postman = Postmans.get_impl_clazz('cffi').create()
|
|
123
|
+
postman = postman or cls.new_postman(session=True)
|
|
111
124
|
|
|
112
125
|
resp = postman.get(cls.JM_PUB_URL)
|
|
113
126
|
if resp.status_code != 200:
|
|
@@ -204,6 +204,9 @@ class JmPhotoDetail(WorkEntity):
|
|
|
204
204
|
def __len__(self):
|
|
205
205
|
return len(self.page_arr)
|
|
206
206
|
|
|
207
|
+
def __iter__(self) -> Generator[JmImageDetail, Any, None]:
|
|
208
|
+
return super().__iter__()
|
|
209
|
+
|
|
207
210
|
|
|
208
211
|
class JmAlbumDetail(WorkEntity):
|
|
209
212
|
|
|
@@ -297,6 +300,9 @@ class JmAlbumDetail(WorkEntity):
|
|
|
297
300
|
|
|
298
301
|
return ret
|
|
299
302
|
|
|
303
|
+
def __iter__(self) -> Generator[JmPhotoDetail, Any, None]:
|
|
304
|
+
return super().__iter__()
|
|
305
|
+
|
|
300
306
|
|
|
301
307
|
class JmSearchPage(IterableEntity):
|
|
302
308
|
|
|
@@ -1,68 +1,6 @@
|
|
|
1
1
|
from .jm_client_impl import *
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
class JmOptionAdvice:
|
|
5
|
-
|
|
6
|
-
def decide_image_save_dir(self,
|
|
7
|
-
option: 'JmOption',
|
|
8
|
-
photo_detail: JmPhotoDetail,
|
|
9
|
-
) -> StrNone:
|
|
10
|
-
"""
|
|
11
|
-
决定一个本子图片的下载文件夹
|
|
12
|
-
@param option: JmOption对象
|
|
13
|
-
@param photo_detail: 本子章节实体类
|
|
14
|
-
@return: 下载文件夹,为空表示不处理
|
|
15
|
-
"""
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
def decide_image_filepath(self,
|
|
19
|
-
option: 'JmOption',
|
|
20
|
-
photo_detail: JmPhotoDetail,
|
|
21
|
-
index: int,
|
|
22
|
-
) -> StrNone:
|
|
23
|
-
"""
|
|
24
|
-
决定一个本子图片的绝对路径
|
|
25
|
-
@param option: JmOption对象
|
|
26
|
-
@param photo_detail: 本子章节实体类
|
|
27
|
-
@param index: 本子章节里的第几章图片
|
|
28
|
-
@return: 下载绝对路径,为空表示不处理
|
|
29
|
-
"""
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
|
-
def decide_image_suffix(self,
|
|
33
|
-
option: 'JmOption',
|
|
34
|
-
img_detail: JmImageDetail,
|
|
35
|
-
) -> StrNone:
|
|
36
|
-
"""
|
|
37
|
-
决定一个图片的保存后缀名
|
|
38
|
-
@param option: JmOption对象
|
|
39
|
-
@param img_detail: 禁漫图片实体类
|
|
40
|
-
@return: 保存后缀名,为空表示不处理
|
|
41
|
-
"""
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class JmAdviceRegistry:
|
|
46
|
-
advice_registration: Dict[Any, List[JmOptionAdvice]] = {}
|
|
47
|
-
|
|
48
|
-
@classmethod
|
|
49
|
-
def register_advice(cls, base, *advice):
|
|
50
|
-
advice_ls = cls.advice_registration.get(base, None)
|
|
51
|
-
|
|
52
|
-
if advice_ls is None:
|
|
53
|
-
advice_ls = list(advice)
|
|
54
|
-
cls.advice_registration[base] = advice_ls
|
|
55
|
-
else:
|
|
56
|
-
for e in advice:
|
|
57
|
-
advice_ls.append(e)
|
|
58
|
-
|
|
59
|
-
return advice
|
|
60
|
-
|
|
61
|
-
@classmethod
|
|
62
|
-
def get_advice(cls, base) -> List[JmOptionAdvice]:
|
|
63
|
-
return cls.advice_registration.setdefault(base, [])
|
|
64
|
-
|
|
65
|
-
|
|
66
4
|
class DirRule:
|
|
67
5
|
rule_sample = [
|
|
68
6
|
# 根目录 / Album-id / Photo-序号 /
|
|
@@ -205,12 +143,6 @@ class JmOption:
|
|
|
205
143
|
"""
|
|
206
144
|
|
|
207
145
|
def decide_image_save_dir(self, photo_detail) -> str:
|
|
208
|
-
# 先检查advice的回调,如果回调支持,则优先使用回调
|
|
209
|
-
for advice in JmAdviceRegistry.get_advice(self):
|
|
210
|
-
save_dir = advice.decide_image_save_dir(self, photo_detail)
|
|
211
|
-
if save_dir is not None:
|
|
212
|
-
return save_dir
|
|
213
|
-
|
|
214
146
|
# 使用 self.dir_rule 决定 save_dir
|
|
215
147
|
save_dir = self.dir_rule.deside_image_save_dir(
|
|
216
148
|
photo_detail.from_album,
|
|
@@ -221,12 +153,6 @@ class JmOption:
|
|
|
221
153
|
return save_dir
|
|
222
154
|
|
|
223
155
|
def decide_image_suffix(self, img_detail: JmImageDetail):
|
|
224
|
-
# 先检查advice的回调,如果回调支持,则优先使用回调
|
|
225
|
-
for advice in JmAdviceRegistry.get_advice(self):
|
|
226
|
-
suffix = advice.decide_image_suffix(self, img_detail)
|
|
227
|
-
if suffix is not None:
|
|
228
|
-
return suffix
|
|
229
|
-
|
|
230
156
|
# 动图则使用原后缀
|
|
231
157
|
suffix = img_detail.img_file_suffix
|
|
232
158
|
if suffix.endswith("gif"):
|
|
@@ -236,25 +162,12 @@ class JmOption:
|
|
|
236
162
|
return self.download_image_suffix or suffix
|
|
237
163
|
|
|
238
164
|
def decide_image_filepath(self, photo_detail: JmPhotoDetail, index: int) -> str:
|
|
239
|
-
# 先检查advice的回调,如果回调支持,则优先使用回调
|
|
240
|
-
for advice in JmAdviceRegistry.get_advice(self):
|
|
241
|
-
filepath = advice.decide_image_filepath(self, photo_detail, index)
|
|
242
|
-
if filepath is not None:
|
|
243
|
-
return filepath
|
|
244
|
-
|
|
245
165
|
# 通过拼接生成绝对路径
|
|
246
166
|
save_dir = self.decide_image_save_dir(photo_detail)
|
|
247
167
|
image: JmImageDetail = photo_detail[index]
|
|
248
168
|
suffix = self.decide_image_suffix(image)
|
|
249
169
|
return save_dir + image.img_file_name + suffix
|
|
250
170
|
|
|
251
|
-
"""
|
|
252
|
-
下面是对Advice的支持
|
|
253
|
-
"""
|
|
254
|
-
|
|
255
|
-
def register_advice(self, *advice):
|
|
256
|
-
JmAdviceRegistry.register_advice(self, *advice)
|
|
257
|
-
|
|
258
171
|
"""
|
|
259
172
|
下面是创建对象相关方法
|
|
260
173
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|