Skip to content

Commit fc3842f

Browse files
authored
v2.3.4: 支持Client自动配置域名,优化模块配置类,跟进项目文档 (#144)
今后GitHub Actions默认采用移动端实现
1 parent 49e6d26 commit fc3842f

17 files changed

+282
-133
lines changed

README.md

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
**友情提示:珍爱JM,为了减轻JM的服务器压力,请不要一次性爬取太多本子,西门🙏🙏🙏**.
88

9-
10-
119
## 安装教程
1210

1311
* 通过pip官方源安装(推荐,并且更新也是这个命令)
@@ -21,8 +19,6 @@
2119
pip install -e ./
2220
```
2321

24-
25-
2622
## 快速上手
2723

2824
使用下面的两行代码,即可实现功能:把某个本子(album)里的所有章节(photo)下载到本地
@@ -45,14 +41,13 @@ $ jmcomic 422866
4541
# 更多用法请参考文件 usage/usage_cl.py (命令行使用介绍)
4642
```
4743

48-
49-
5044
## 进阶使用
5145

5246
进阶使用可以参考本repo下usage文件夹内的示例代码文件,下面是各个文件的作用,你可以挑感兴趣的阅读:
5347

5448
- API上手介绍: `getting_started.py`
5549
- 命令行使用介绍: `usage_cl.py`
50+
- 配置客户端的实现(网页端、移动端): `usage_configure_client_impl.py`
5651
- 使用API实现简单功能: `usage_simple.py`
5752
- 演示jmcomic模块的可自定义功能点: `usage_custom.py`
5853
- 使用API的Filter过滤功能: `usage_feature_filter.py`
@@ -66,39 +61,33 @@ $ jmcomic 422866
6661
- 测试你的ip可以访问哪些禁漫域名: `pick_domain.py`
6762
- 基于GitHub Actions下载本子: `workflow_download.py`
6863

69-
70-
7164
## 项目特点
7265

7366
- **绕过Cloudflare的反爬虫**
7467
- 支持使用**命令行**下载本子,无需写Python代码,简单易用
7568
- 支持使用**GitHub Actions**下载本子,网页上直接输入本子id就能下载([教程:使用GitHub Actions下载禁漫本子](./assets/docs/教程:使用GitHub%20Actions下载禁漫本子.md)
69+
- 支持**网页端****移动端**两种客户端实现,可通过配置切换(**移动端不限ip兼容性好,网页端限制ip地区但效率高**
70+
- 支持**自动重试和域名切换**机制
71+
- **多线程下载**(可细化到一图一线程,效率极高)
72+
- 跟进了JM最新的图片分割算法(2023-02-08)
7673
- **可配置性强**
74+
7775
- 不配置也能使用,十分方便
7876
- 配置可以从**配置文件**生成,支持多种文件格式
79-
- 配置点有:`是否使用磁盘缓存` `并发下载图片数` `图片类型转换` `下载路径` `请求元信息(headers,cookies,proxies)`
77+
- 配置点有:`请求域名` `客户端实现` `是否使用磁盘缓存` `同时下载的章节/图片数量` `图片格式转换` `下载路径规则` `请求元信息(headers,cookies,proxies)`
8078
- **可扩展性强**
79+
8180
- **支持Plugin插件,可以方便地扩展功能,以及使用别人的插件**
8281
- 目前内置支持的插件有:`登录插件` `硬件占用监控插件` `只下载新章插件` `压缩文件插件`
8382
- 支持自定义本子/章节/图片下载前后的回调函数
8483
- 支持自定义debug日志
85-
- 支持自定义类:Downloader(负责调度)/Option(负责配置)/Client(负责请求)/实体类 等等
86-
- ......
87-
- 支持**自动重试和域名切换**机制
88-
- **多线程下载**(可细化到一图一线程,效率极高)
89-
- 跟进了JM最新的图片分割算法(2023-02-08)
90-
91-
92-
84+
- 支持自定义类:`Downloader(负责调度)` `Option(负责配置)` `Client(负责请求)` `实体类`
9385

9486
## 使用小说明
9587

9688
* Python >= 3.7
9789
* 个人项目,文档和示例会有不及时之处,可以Issue提问
9890

99-
100-
101-
10291
## 项目文件夹介绍
10392

10493
* assets:存放一些非代码的资源文件
@@ -111,8 +100,6 @@ $ jmcomic 422866
111100
* tests:测试目录,存放测试代码,使用unittest
112101
* usage:用法目录,存放示例/使用代码
113102

114-
115-
116103
## 感谢以下项目
117104

118105
### 图片分割算法代码+禁漫移动端API
Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
# GitHub Actions 下载脚本配置
2-
version: '2.0'
3-
42
dir_rule:
53
base_dir: ${JM_DOWNLOAD_DIR}
64
rule: Bd_Aauthor_Atitle_Pindex
75

8-
96
client:
10-
domain:
11-
- jmcomic1.me
12-
- jmcomic.me
7+
impl: api
8+
domain: [
9+
"www.jmapinode1.cc",
10+
"www.jmapinode2.cc",
11+
"www.jmapinode3.cc",
12+
"www.jmapibranch2.cc",
13+
]
1314

1415
# 插件配置
1516
plugin:
@@ -18,10 +19,3 @@ plugin:
1819
kwargs:
1920
interval: 0.5 # 间隔时间
2021
enable_warning: false # 不告警
21-
22-
# after_album:
23-
# - plugin: zip # 压缩文件插件
24-
# kwargs:
25-
# level: album # 按照章节,一个章节一个压缩文件
26-
# filename_rule: Atitle # 压缩文件的命名规则
27-
# zip_dir: ${JM_ZIP_DIR} # 压缩文件存放的文件夹

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.3.3'
5+
__version__ = '2.3.4'
66

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

src/jmcomic/jm_client_impl.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from .jm_client_interface import *
22

33

4+
# 抽象基类,实现了域名管理,发请求,重试机制,debug,缓存等功能
45
class AbstractJmClient(
56
JmcomicClient,
67
PostmanProxy,
78
):
8-
client_key: None
9+
client_key = None
910

1011
def __init__(self,
1112
postman: Postman,
@@ -145,11 +146,11 @@ def wrap_func_cache(func_name, cache_dict_name):
145146
def is_cache_enabled(self) -> bool:
146147
return getattr(self, '__enable_cache__', False)
147148

148-
def get_jmcomic_url(self, postman=None):
149-
return JmModuleConfig.get_jmcomic_url(postman or self.get_root_postman())
149+
def get_html_domain(self, postman=None):
150+
return JmModuleConfig.get_html_domain(postman or self.get_root_postman())
150151

151-
def get_jmcomic_domain_all(self, postman=None):
152-
return JmModuleConfig.get_jmcomic_domain_all(postman or self.get_root_postman())
152+
def get_html_domain_all(self, postman=None):
153+
return JmModuleConfig.get_html_domain_all(postman or self.get_root_postman())
153154

154155
def get_domain_list(self):
155156
return self.domain_list
@@ -390,6 +391,7 @@ def check_special_http_code(cls, resp):
390391
)
391392

392393

394+
# 基于禁漫移动端(APP)实现的JmClient
393395
class JmApiClient(AbstractJmClient):
394396
client_key = 'api'
395397
API_SEARCH = '/search'

src/jmcomic/jm_client_interface.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -373,14 +373,22 @@ class JmcomicClient(
373373
JmSearchAlbumClient,
374374
Postman,
375375
):
376-
def get_jmcomic_url(self):
377-
return JmModuleConfig.get_jmcomic_url()
378-
379-
def get_jmcomic_domain_all(self):
380-
return JmModuleConfig.get_jmcomic_domain_all()
376+
client_key: None
381377

382378
def get_domain_list(self) -> List[str]:
379+
"""
380+
获取当前client的域名配置
381+
"""
383382
raise NotImplementedError
384383

385384
def set_domain_list(self, domain_list: List[str]):
385+
"""
386+
设置当前client的域名配置
387+
"""
386388
raise NotImplementedError
389+
390+
def get_html_domain(self):
391+
return JmModuleConfig.get_html_domain()
392+
393+
def get_html_domain_all(self):
394+
return JmModuleConfig.get_html_domain_all()

src/jmcomic/jm_config.py

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,27 @@ class JmModuleConfig:
5252
SCRAMBLE_NUM_8 = 421926 # 2023-02-08后改了图片切割算法
5353
SCRAMBLE_CACHE = {}
5454

55-
# API的相关配置
56-
# 移动端api密钥
55+
# 移动端API的相关配置
56+
# API密钥
5757
MAGIC_18COMICAPPCONTENT = '18comicAPPContent'
58-
# 移动端的图片域名
59-
DOMAIN_IMAGE_LIST = [f"cdn-msp.jmapiproxy{i}.cc" for i in range(1, 4)]
6058

61-
# 下载时的一些默认值配置
62-
default_author = 'default-author'
63-
64-
# 模块级别的可重写配置
65-
DOMAIN = None
66-
DOMAIN_LIST = None
59+
# 域名配置 - 移动端
60+
# 图片域名
61+
DOMAIN_API_IMAGE_LIST = [f"cdn-msp.jmapiproxy{i}.cc" for i in range(1, 4)]
62+
# API域名
63+
DOMAIN_API_LIST = [
64+
"www.jmapinode1.cc",
65+
"www.jmapinode2.cc",
66+
"www.jmapinode3.cc",
67+
"www.jmapibranch2.cc",
68+
]
69+
70+
# 域名配置 - 网页端
71+
# 无需配置,默认为None,需要的时候会发起请求获得
72+
DOMAIN_HTML = None
73+
DOMAIN_HTML_LIST = None
74+
75+
# 模块级别的可重写类配置
6776
CLASS_DOWNLOADER = None
6877
CLASS_OPTION = None
6978
CLASS_ALBUM = None
@@ -86,6 +95,8 @@ class JmModuleConfig:
8695
enable_jm_debug = True
8796
# debug时解码url
8897
decode_url_when_debug = True
98+
# 下载时的一些默认值配置
99+
default_author = 'default-author'
89100

90101
@classmethod
91102
def downloader_class(cls):
@@ -139,33 +150,33 @@ def client_impl_class(cls, client_key: str):
139150
return clazz
140151

141152
@classmethod
142-
@field_cache("DOMAIN")
143-
def domain(cls, postman=None):
153+
@field_cache("DOMAIN_HTML")
154+
def get_html_domain(cls, postman=None):
144155
"""
145156
由于禁漫的域名经常变化,调用此方法可以获取一个当前可用的最新的域名 domain,
146157
并且设置把 domain 设置为禁漫模块的默认域名。
147158
这样一来,配置文件也不用配置域名了,一切都在运行时动态获取。
148159
"""
149160
from .jm_toolkit import JmcomicText
150-
return JmcomicText.parse_to_jm_domain(cls.get_jmcomic_url(postman))
161+
return JmcomicText.parse_to_jm_domain(cls.get_html_url(postman))
151162

152163
@classmethod
153-
def get_jmcomic_url(cls, postman=None):
164+
def get_html_url(cls, postman=None):
154165
"""
155166
访问禁漫的永久网域,从而得到一个可用的禁漫网址
156167
@return: https://jm-comic2.cc
157168
"""
158169
postman = postman or cls.new_postman(session=True)
159170

160171
url = postman.with_redirect_catching().get(cls.JM_REDIRECT_URL)
161-
cls.jm_debug('获取禁漫URL', f'[{cls.JM_REDIRECT_URL}] → [{url}]')
172+
cls.jm_debug('获取禁漫网页URL', f'[{cls.JM_REDIRECT_URL}] → [{url}]')
162173
return url
163174

164175
@classmethod
165-
@field_cache("DOMAIN_LIST")
166-
def get_jmcomic_domain_all(cls, postman=None):
176+
@field_cache("DOMAIN_HTML_LIST")
177+
def get_html_domain_all(cls, postman=None):
167178
"""
168-
访问禁漫发布页,得到所有禁漫的域名
179+
访问禁漫发布页,得到所有的禁漫网页域名
169180
170181
@return: ['18comic.vip', ..., 'jm365.xyz/ZNPJam'], 最后一个是【APP軟件下載】
171182
"""
@@ -179,7 +190,7 @@ def get_jmcomic_domain_all(cls, postman=None):
179190
from .jm_toolkit import JmcomicText
180191
domain_list = JmcomicText.analyse_jm_pub_html(resp.text)
181192

182-
cls.jm_debug('获取禁漫全部域名', f'[{resp.url}] → {domain_list}')
193+
cls.jm_debug('获取禁漫网页全部域名', f'[{resp.url}] → {domain_list}')
183194
return domain_list
184195

185196
@classmethod
@@ -240,6 +251,8 @@ def new_postman(cls, session=False, **kwargs):
240251

241252
# option 默认配置字典
242253
JM_OPTION_VER = '2.1'
254+
CLIENT_IMPL_DEFAULT = 'html'
255+
243256
default_option_dict: dict = {
244257
'version': JM_OPTION_VER,
245258
'debug': None,
@@ -262,7 +275,7 @@ def new_postman(cls, session=False, **kwargs):
262275
'headers': None,
263276
}
264277
},
265-
'impl': 'html',
278+
'impl': None,
266279
'retry_times': 5
267280
},
268281
'plugin': {},
@@ -293,10 +306,9 @@ def option_default_dict(cls) -> dict:
293306
if client['cache'] is None:
294307
client['cache'] = True
295308

296-
# headers
297-
meta_data = client['postman']['meta_data']
298-
if meta_data['headers'] is None:
299-
meta_data['headers'] = cls.headers()
309+
# client impl
310+
if client['impl'] is None:
311+
client['impl'] = cls.CLIENT_IMPL_DEFAULT
300312

301313
# threading photo
302314
dt = option_dict['download']['threading']
@@ -312,7 +324,12 @@ def register_plugin(cls, plugin_class):
312324

313325
@classmethod
314326
def register_client(cls, client_class):
315-
cls.CLASS_CLIENT_IMPL[client_class.client_key] = client_class
327+
client_key = getattr(client_class, 'client_key', None)
328+
if client_key is None:
329+
from .jm_toolkit import ExceptionTool
330+
ExceptionTool.raises(f'未配置client_key, class: {client_class}')
331+
332+
cls.CLASS_CLIENT_IMPL[client_key] = client_class
316333

317334

318335
jm_debug = JmModuleConfig.jm_debug

0 commit comments

Comments
 (0)