Skip to content

Commit

Permalink
v2.2.1: 新增一个插件能够实时监控硬件占用率,优化插件配置语法,更新文档 (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
hect0x7 authored Aug 31, 2023
1 parent d019d97 commit c6e8d69
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 47 deletions.
14 changes: 8 additions & 6 deletions .github/workflows/download.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,19 @@ jobs:
with:
python-version: "3.11"

- name: 安装依赖项(pip)
if: ${{ github.ref == 'refs/heads/workflow' }}
- name: Install Dependency
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: 安装jmcomic(pip)
if: ${{ github.ref != 'refs/heads/dev' }}
run: |
pip install jmcomic -i https://pypi.org/project --upgrade
- name: 安装依赖项(local)
if: ${{ github.ref != 'refs/heads/workflow' }}
- name: 安装jmcomic(local)
if: ${{ github.ref == 'refs/heads/dev' }}
run: |
python -m pip install --upgrade pip
pip install commonX -i https://pypi.org/project --upgrade
pip install -e ./
- name: 运行下载脚本
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/download_dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,19 @@ jobs:
with:
python-version: "3.11"

- name: 安装依赖项(pip)
if: ${{ github.ref != 'refs/heads/dev' }}
- name: Install Dependency
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: 安装jmcomic(pip)
if: ${{ github.ref != 'refs/heads/dev' }}
run: |
pip install jmcomic -i https://pypi.org/project --upgrade
- name: 安装依赖项(local)
- name: 安装jmcomic(local)
if: ${{ github.ref == 'refs/heads/dev' }}
run: |
python -m pip install --upgrade pip
pip install commonX -i https://pypi.org/project --upgrade
pip install -e ./
- name: 运行下载脚本
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载
- 演示jmcomic模块的自定义功能点: `usage_custom.py`
- 演示jmcomic模块的Plugin插件体系: `usage_plugin.py`


## 项目特点

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

Expand Down
12 changes: 9 additions & 3 deletions assets/config/option_plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

plugin:
after_init:
login:
username: un
password: pw
- plugin: usage-log # 实时打印硬件占用率的插件
kwargs:
interval: 0.5 # 间隔时间
enable_warning: true

- plugin: login # 登录插件
kwargs:
username: un
password: pw
8 changes: 8 additions & 0 deletions assets/config/option_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@ client:
domain:
- jmcomic1.me
- jmcomic.me

# 插件配置
plugin:
after_init:
- plugin: usage-log # 实时打印硬件占用率的插件
kwargs:
interval: 0.5 # 间隔时间
enable_warning: false # 不告警
8 changes: 8 additions & 0 deletions assets/config/option_workflow_download.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,11 @@ client:
domain:
- jmcomic1.me
- jmcomic.me

# 插件配置
plugin:
after_init:
- plugin: usage-log # 实时打印硬件占用率的插件
kwargs:
interval: 0.5 # 间隔时间
enable_warning: false # 不告警
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ commonX
curl_cffi
PyYAML
Pillow
psutil
2 changes: 1 addition & 1 deletion src/jmcomic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# 被依赖方 <--- 使用方
# config <--- entity <--- toolkit <--- client <--- option <--- downloader

__version__ = '2.2.0'
__version__ = '2.2.1'

from .api import *
from .jm_plugin import *
13 changes: 7 additions & 6 deletions src/jmcomic/jm_option.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,20 +303,21 @@ def download_album(self, photo_id):
download_album(photo_id, self)

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

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

plugin_registry = JmModuleConfig.plugin_registry
for name, kwargs in plugin_dict.items():
plugin_class: Optional[Type[JmOptionPlugin]] = plugin_registry.get(name, None)
for pinfo in plugin_list:
key, kwargs = pinfo['plugin'], pinfo['kwargs']
plugin_class: Optional[Type[JmOptionPlugin]] = plugin_registry.get(key, None)

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

self.invoke_plugin(plugin_class, kwargs)

Expand Down
98 changes: 93 additions & 5 deletions src/jmcomic/jm_plugin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""
该文件存放的是option插件类
该文件存放的是option扩展功能类
"""

from .jm_option import *
from .jm_option import JmOption, JmModuleConfig, jm_debug


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


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


class LoginPlugin(JmOptionPlugin):
class JmLoginPlugin(JmOptionPlugin):
plugin_key = 'login'

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


JmModuleConfig.register_plugin(LoginPlugin)
class UsageLogPlugin(JmOptionPlugin):
plugin_key = 'usage-log'

def invoke(self, **kwargs) -> None:
import threading
threading.Thread(
target=self.monitor_resource_usage,
kwargs=kwargs,
daemon=True,
).start()

def monitor_resource_usage(
self,
interval=1,
enable_warning=True,
warning_cpu_percent=70,
warning_mem_percent=50,
warning_thread_count=100,
):
try:
import psutil
except ImportError:
msg = (f'插件`{self.plugin_key}`依赖psutil库,请先安装psutil再使用。'
f'安装命令: [pip install psutil]')
import warnings
warnings.warn(msg)
# import sys
# print(msg, file=sys.stderr)
return

from time import sleep
from threading import active_count
# 获取当前进程
process = psutil.Process()

cpu_percent = None
# noinspection PyUnusedLocal
thread_count = None
# noinspection PyUnusedLocal
mem_usage = None

def warning():
warning_msg_list = []
if cpu_percent >= warning_cpu_percent:
warning_msg_list.append(f'进程占用cpu过高 ({cpu_percent}% >= {warning_cpu_percent}%)')

mem_percent = psutil.virtual_memory().percent
if mem_percent >= warning_mem_percent:
warning_msg_list.append(f'系统内存占用过高 ({mem_percent}% >= {warning_mem_percent}%)')

if thread_count >= warning_thread_count:
warning_msg_list.append(f'线程数过多 ({thread_count} >= {warning_thread_count})')

if len(warning_msg_list) != 0:
warning_msg_list.insert(0, '硬件占用告警,占用过高可能导致系统卡死!')
warning_msg_list.append('')
jm_debug('plugin.psutil.warning', '\n'.join(warning_msg_list))

while True:
# 获取CPU占用率(0~100)
cpu_percent = process.cpu_percent()
# 获取内存占用(MB)
mem_usage = round(process.memory_info().rss / 1024 / 1024, 2)
thread_count = active_count()
# 获取网络占用情况
# network_info = psutil.net_io_counters()
# network_bytes_sent = network_info.bytes_sent
# network_bytes_received = network_info.bytes_recv

# 打印信息
msg = ', '.join([
f'线程数: {thread_count}',
f'CPU占用: {cpu_percent}%',
f'内存占用: {mem_usage}MB',
# f"发送的字节数: {network_bytes_sent}",
# f"接收的字节数: {network_bytes_received}",
])
jm_debug('plugin.psutil.log', msg)

if enable_warning is True:
# 警告
warning()

# 等待一段时间
sleep(interval)


JmModuleConfig.register_plugin(JmLoginPlugin)
JmModuleConfig.register_plugin(UsageLogPlugin)
33 changes: 16 additions & 17 deletions usage/usage_plugin.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
"""
plugin(扩展/插件)是jmcomic=2.2.0新引入的机制,
plugin机制可以实现在`特定时间` 回调 `特定插件`,实现灵活无感知的功能增强。
目前仅支持一个时机: after_init,表示在option对象的 __init__ 初始化方法的最后
目前仅内置一个插件: login,实现的功能为:登录禁漫,并保存登录后的cookies,让所有client都带上此cookies。实现类是
你可以在option配置文件当中,配置如下内容,来实现在 after_init 时机,调用 login 插件
plugin机制可以实现在`特定时间` 回调 `特定插件`,实现灵活无感知的功能增强,
目前仅支持一个时机: after_init,表示在option对象的 __init__ 初始化方法的最后。
下面以内置插件[login]为例:
插件功能:登录JM,获取并保存cookies。
你可以在option配置文件当中,配置如下内容,来实现在 after_init 时机,调用login插件。
plugin:
after_init: # 时机
login: # 插件的key
# 下面是给插件的参数 (kwargs),由插件类自定义
username: un
password: pw
- plugin: login # 插件的key
kwargs:
# 下面是给插件的参数 (kwargs),由插件类自定义
username: un # 禁漫帐号
password: pw # 密码
你也可以自定义插件和插件时机
自定义插件时机需要你重写Option类,示例请见 usage_custom
下面演示自定义插件,分为3步:
1. 自定义plugin类
2. 让plugin类失效
2. 让plugin类生效
3. 使用plugin的key
如果你有好的plugin想法,也欢迎向我提PR,将你的plugin内置到jmcomic模块中
Expand All @@ -42,15 +40,16 @@ def invoke(self, hello_plugin) -> None:
print(hello_plugin)


# 2. 让plugin类失效
# 2. 让plugin类生效
JmModuleConfig.register_plugin(MyPlugin)

# 3. 使用plugin的key
# 3. 在配置文件中使用plugin
"""
plugin:
after_init: # 时机
myplugin: # 插件的key
hello_plugin: this is my plugin invoke method's parameter # 你自定义的插件的参数
- plugin: myplugin # 插件的key
kwargs:
hello_plugin: this is my plugin invoke method's parameter # 你自定义的插件的参数
"""

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

0 comments on commit c6e8d69

Please sign in to comment.