Skip to content

Commit c6e8d69

Browse files
authored
v2.2.1: 新增一个插件能够实时监控硬件占用率,优化插件配置语法,更新文档 (#117)
1 parent d019d97 commit c6e8d69

11 files changed

+162
-47
lines changed

.github/workflows/download.yml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@ jobs:
2727
with:
2828
python-version: "3.11"
2929

30-
- name: 安装依赖项(pip)
31-
if: ${{ github.ref == 'refs/heads/workflow' }}
30+
- name: Install Dependency
3231
run: |
3332
python -m pip install --upgrade pip
33+
pip install -r requirements-dev.txt
34+
35+
- name: 安装jmcomic(pip)
36+
if: ${{ github.ref != 'refs/heads/dev' }}
37+
run: |
3438
pip install jmcomic -i https://pypi.org/project --upgrade
3539
36-
- name: 安装依赖项(local)
37-
if: ${{ github.ref != 'refs/heads/workflow' }}
40+
- name: 安装jmcomic(local)
41+
if: ${{ github.ref == 'refs/heads/dev' }}
3842
run: |
39-
python -m pip install --upgrade pip
40-
pip install commonX -i https://pypi.org/project --upgrade
4143
pip install -e ./
4244
4345
- name: 运行下载脚本

.github/workflows/download_dispatch.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,19 @@ jobs:
6161
with:
6262
python-version: "3.11"
6363

64-
- name: 安装依赖项(pip)
65-
if: ${{ github.ref != 'refs/heads/dev' }}
64+
- name: Install Dependency
6665
run: |
6766
python -m pip install --upgrade pip
67+
pip install -r requirements-dev.txt
68+
69+
- name: 安装jmcomic(pip)
70+
if: ${{ github.ref != 'refs/heads/dev' }}
71+
run: |
6872
pip install jmcomic -i https://pypi.org/project --upgrade
6973
70-
- name: 安装依赖项(local)
74+
- name: 安装jmcomic(local)
7175
if: ${{ github.ref == 'refs/heads/dev' }}
7276
run: |
73-
python -m pip install --upgrade pip
74-
pip install commonX -i https://pypi.org/project --upgrade
7577
pip install -e ./
7678
7779
- name: 运行下载脚本

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,22 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
4343
- 演示jmcomic模块的自定义功能点: `usage_custom.py`
4444
- 演示jmcomic模块的Plugin插件体系: `usage_plugin.py`
4545

46-
4746
## 项目特点
4847

4948
- **绕过Cloudflare的反爬虫**
50-
- 支持使用**GitHub Actions**下载漫画,不会编程都能用[教程:使用GitHub Actions下载禁漫本子](./assets/docs/教程:使用GitHub%20Actions下载禁漫本子.md)
49+
- 支持使用**GitHub Actions**下载本子,网页上直接输入本子id就能下载[教程:使用GitHub Actions下载禁漫本子](./assets/docs/教程:使用GitHub%20Actions下载禁漫本子.md)
5150
- **可配置性强**
5251
- 不配置也能使用,十分方便
5352
- 配置可以从**配置文件**生成,支持多种文件格式,无需写Python代码
5453
- 配置点有:`是否使用磁盘缓存` `并发下载图片数` `图片类型转换` `下载路径` `请求元信息(headers,cookies,proxies)`
5554
- **可扩展性强**
5655
- **支持Plugin插件,可以方便地扩展功能,以及使用别人的插件**
56+
- 目前内置支持的插件:`登录插件``硬件占用监控插件`
5757
- 支持自定义本子/章节/图片下载前后的回调函数
5858
- 支持自定义debug日志的开关/格式
5959
- 支持自定义Downloader/Option/Client/实体类
60-
- ...
61-
- 支持自动重试和域名切换机制
60+
- ......
61+
- 支持**自动重试和域名切换**机制
6262
- **多线程下载**(可细化到一图一线程,效率极高)
6363
- 跟进了JM最新的图片分割算法(2023-02-08)
6464

assets/config/option_plugin.yml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
plugin:
44
after_init:
5-
login:
6-
username: un
7-
password: pw
5+
- plugin: usage-log # 实时打印硬件占用率的插件
6+
kwargs:
7+
interval: 0.5 # 间隔时间
8+
enable_warning: true
9+
10+
- plugin: login # 登录插件
11+
kwargs:
12+
username: un
13+
password: pw

assets/config/option_test.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,11 @@ client:
55
domain:
66
- jmcomic1.me
77
- jmcomic.me
8+
9+
# 插件配置
10+
plugin:
11+
after_init:
12+
- plugin: usage-log # 实时打印硬件占用率的插件
13+
kwargs:
14+
interval: 0.5 # 间隔时间
15+
enable_warning: false # 不告警

assets/config/option_workflow_download.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ client:
1010
domain:
1111
- jmcomic1.me
1212
- jmcomic.me
13+
14+
# 插件配置
15+
plugin:
16+
after_init:
17+
- plugin: usage-log # 实时打印硬件占用率的插件
18+
kwargs:
19+
interval: 0.5 # 间隔时间
20+
enable_warning: false # 不告警

requirements-dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ commonX
22
curl_cffi
33
PyYAML
44
Pillow
5+
psutil

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.2.0'
5+
__version__ = '2.2.1'
66

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

src/jmcomic/jm_option.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,21 @@ def download_album(self, photo_id):
303303
download_album(photo_id, self)
304304

305305
# 下面的方法为调用插件提供支持
306-
def call_all_plugin(self, key: str):
307-
plugin_dict: dict = self.plugin.get(key, {})
308-
if plugin_dict is None or len(plugin_dict) == 0:
306+
def call_all_plugin(self, group: str):
307+
plugin_list: List[dict] = self.plugin.get(group, [])
308+
if plugin_list is None or len(plugin_list) == 0:
309309
return
310310

311311
# 保证 jm_plugin.py 被加载
312312
from .jm_plugin import JmOptionPlugin
313313

314314
plugin_registry = JmModuleConfig.plugin_registry
315-
for name, kwargs in plugin_dict.items():
316-
plugin_class: Optional[Type[JmOptionPlugin]] = plugin_registry.get(name, None)
315+
for pinfo in plugin_list:
316+
key, kwargs = pinfo['plugin'], pinfo['kwargs']
317+
plugin_class: Optional[Type[JmOptionPlugin]] = plugin_registry.get(key, None)
317318

318319
if plugin_class is None:
319-
raise JmModuleConfig.exception(f'[{key}] 未注册的plugin: {name}')
320+
raise JmModuleConfig.exception(f'[{group}] 未注册的plugin: {key}')
320321

321322
self.invoke_plugin(plugin_class, kwargs)
322323

src/jmcomic/jm_plugin.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
"""
2-
该文件存放的是option插件类
2+
该文件存放的是option扩展功能类
33
"""
44

5-
from .jm_option import *
5+
from .jm_option import JmOption, JmModuleConfig, jm_debug
66

77

88
class JmOptionPlugin:
@@ -28,11 +28,11 @@ def build(cls, option: JmOption) -> 'JmOptionPlugin':
2828

2929

3030
"""
31-
插件功能:登录禁漫,并保存登录后的cookies,让所有client都带上此cookies
31+
扩展功能:登录禁漫,并保存登录后的cookies,让所有client都带上此cookies
3232
"""
3333

3434

35-
class LoginPlugin(JmOptionPlugin):
35+
class JmLoginPlugin(JmOptionPlugin):
3636
plugin_key = 'login'
3737

3838
def invoke(self, username, password) -> None:
@@ -50,4 +50,92 @@ def invoke(self, username, password) -> None:
5050
jm_debug('plugin.login', '登录成功')
5151

5252

53-
JmModuleConfig.register_plugin(LoginPlugin)
53+
class UsageLogPlugin(JmOptionPlugin):
54+
plugin_key = 'usage-log'
55+
56+
def invoke(self, **kwargs) -> None:
57+
import threading
58+
threading.Thread(
59+
target=self.monitor_resource_usage,
60+
kwargs=kwargs,
61+
daemon=True,
62+
).start()
63+
64+
def monitor_resource_usage(
65+
self,
66+
interval=1,
67+
enable_warning=True,
68+
warning_cpu_percent=70,
69+
warning_mem_percent=50,
70+
warning_thread_count=100,
71+
):
72+
try:
73+
import psutil
74+
except ImportError:
75+
msg = (f'插件`{self.plugin_key}`依赖psutil库,请先安装psutil再使用。'
76+
f'安装命令: [pip install psutil]')
77+
import warnings
78+
warnings.warn(msg)
79+
# import sys
80+
# print(msg, file=sys.stderr)
81+
return
82+
83+
from time import sleep
84+
from threading import active_count
85+
# 获取当前进程
86+
process = psutil.Process()
87+
88+
cpu_percent = None
89+
# noinspection PyUnusedLocal
90+
thread_count = None
91+
# noinspection PyUnusedLocal
92+
mem_usage = None
93+
94+
def warning():
95+
warning_msg_list = []
96+
if cpu_percent >= warning_cpu_percent:
97+
warning_msg_list.append(f'进程占用cpu过高 ({cpu_percent}% >= {warning_cpu_percent}%)')
98+
99+
mem_percent = psutil.virtual_memory().percent
100+
if mem_percent >= warning_mem_percent:
101+
warning_msg_list.append(f'系统内存占用过高 ({mem_percent}% >= {warning_mem_percent}%)')
102+
103+
if thread_count >= warning_thread_count:
104+
warning_msg_list.append(f'线程数过多 ({thread_count} >= {warning_thread_count})')
105+
106+
if len(warning_msg_list) != 0:
107+
warning_msg_list.insert(0, '硬件占用告警,占用过高可能导致系统卡死!')
108+
warning_msg_list.append('')
109+
jm_debug('plugin.psutil.warning', '\n'.join(warning_msg_list))
110+
111+
while True:
112+
# 获取CPU占用率(0~100)
113+
cpu_percent = process.cpu_percent()
114+
# 获取内存占用(MB)
115+
mem_usage = round(process.memory_info().rss / 1024 / 1024, 2)
116+
thread_count = active_count()
117+
# 获取网络占用情况
118+
# network_info = psutil.net_io_counters()
119+
# network_bytes_sent = network_info.bytes_sent
120+
# network_bytes_received = network_info.bytes_recv
121+
122+
# 打印信息
123+
msg = ', '.join([
124+
f'线程数: {thread_count}',
125+
f'CPU占用: {cpu_percent}%',
126+
f'内存占用: {mem_usage}MB',
127+
# f"发送的字节数: {network_bytes_sent}",
128+
# f"接收的字节数: {network_bytes_received}",
129+
])
130+
jm_debug('plugin.psutil.log', msg)
131+
132+
if enable_warning is True:
133+
# 警告
134+
warning()
135+
136+
# 等待一段时间
137+
sleep(interval)
138+
139+
140+
JmModuleConfig.register_plugin(JmLoginPlugin)
141+
JmModuleConfig.register_plugin(UsageLogPlugin)

usage/usage_plugin.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,26 @@
11
"""
22
plugin(扩展/插件)是jmcomic=2.2.0新引入的机制,
3-
plugin机制可以实现在`特定时间` 回调 `特定插件`,实现灵活无感知的功能增强。
4-
5-
6-
目前仅支持一个时机: after_init,表示在option对象的 __init__ 初始化方法的最后
7-
目前仅内置一个插件: login,实现的功能为:登录禁漫,并保存登录后的cookies,让所有client都带上此cookies。实现类是
8-
9-
你可以在option配置文件当中,配置如下内容,来实现在 after_init 时机,调用 login 插件
3+
plugin机制可以实现在`特定时间` 回调 `特定插件`,实现灵活无感知的功能增强,
4+
目前仅支持一个时机: after_init,表示在option对象的 __init__ 初始化方法的最后。
105
6+
下面以内置插件[login]为例:
7+
插件功能:登录JM,获取并保存cookies。
8+
你可以在option配置文件当中,配置如下内容,来实现在 after_init 时机,调用login插件。
119
1210
plugin:
1311
after_init: # 时机
14-
login: # 插件的key
15-
# 下面是给插件的参数 (kwargs),由插件类自定义
16-
username: un
17-
password: pw
18-
12+
- plugin: login # 插件的key
13+
kwargs:
14+
# 下面是给插件的参数 (kwargs),由插件类自定义
15+
username: un # 禁漫帐号
16+
password: pw # 密码
1917
2018
你也可以自定义插件和插件时机
2119
自定义插件时机需要你重写Option类,示例请见 usage_custom
2220
下面演示自定义插件,分为3步:
2321
2422
1. 自定义plugin类
25-
2. 让plugin类失效
23+
2. 让plugin类生效
2624
3. 使用plugin的key
2725
2826
如果你有好的plugin想法,也欢迎向我提PR,将你的plugin内置到jmcomic模块中
@@ -42,15 +40,16 @@ def invoke(self, hello_plugin) -> None:
4240
print(hello_plugin)
4341

4442

45-
# 2. 让plugin类失效
43+
# 2. 让plugin类生效
4644
JmModuleConfig.register_plugin(MyPlugin)
4745

48-
# 3. 使用plugin的key
46+
# 3. 在配置文件中使用plugin
4947
"""
5048
plugin:
5149
after_init: # 时机
52-
myplugin: # 插件的key
53-
hello_plugin: this is my plugin invoke method's parameter # 你自定义的插件的参数
50+
- plugin: myplugin # 插件的key
51+
kwargs:
52+
hello_plugin: this is my plugin invoke method's parameter # 你自定义的插件的参数
5453
"""
5554

5655
# 当你使用上述配置文件创建option时,

0 commit comments

Comments
 (0)