v2.2.2: 实现两个内置插件:find_update和zip,优化文档和代码示例 (#118) (#95)

This commit is contained in:
hect0x7 2023-08-31 17:30:12 +08:00 committed by GitHub
parent c6e8d69fc8
commit a847b922ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 628 additions and 85 deletions

View File

@ -4,12 +4,11 @@ on:
workflow_dispatch:
push:
branches: [ "dev" ]
paths-ignore:
- 'src/**/__init__.py'
- '.github/workflows/*'
- 'usage/workflow_download.py'
- 'assets/config/option_workflow_download.yml'
- 'assets/docs/*'
paths:
- 'src/**/*.py'
- 'test/**/*.py'
- '.github/workflows/test.yml'
- 'assets/config/option_test.yml'
jobs:
test: # This code is based on https://github.com/gaogaotiantian/viztracer/blob/master/.github/workflows/python-package.yml

View File

@ -6,6 +6,8 @@
**友情提示珍爱JM为了减轻JM的服务器压力请不要一次性爬取太多本子西门🙏🙏🙏**.
## 安装教程
* 通过pip官方源安装推荐并且更新也是这个命令
@ -19,6 +21,8 @@
pip install -e ./
```
## 快速上手
使用下面的两行代码即可实现功能把某个本子album里的所有章节photo下载到本地
@ -33,15 +37,28 @@ jmcomic.download_album('422866') # 传入要下载的album的id即可下载
# 如果你想要配置,请参考文件 assets/config/常用配置介绍.yml
```
进阶使用可以参考本repo下usage文件夹内的示例代码文件:
## 进阶使用
进阶使用可以参考本repo下usage文件夹内的示例代码文件下面是各个文件的作用你可以挑感兴趣的阅读
- API上手介绍: `getting_started.py`
- 使用API实现简单功能: `usage_simple.py`
- 演示jmcomic模块的可自定义功能点: `usage_custom.py`
- 使用API的Filter过滤功能: `usage_feature_filter.py`
- 演示jmcomic模块的Plugin插件体系: `usage_feature_plugin.py`
- 演示一个综合使用实例: `usage_advanced.py`
- 包括6个功能需求的介绍、实现方案和完整运行日志
- 实现方案非常简洁充分jmcomic的便利性以及强大的插件扩展机制
以及一些趣味用法:
- 测试你的ip可以访问哪些禁漫域名: `pick_domain.py`
- 基于GitHub Actions下载本子: `workflow_download.py`
- 演示jmcomic模块的自定义功能点: `usage_custom.py`
- 演示jmcomic模块的Plugin插件体系: `usage_plugin.py`
## 项目特点
@ -53,7 +70,7 @@ jmcomic.download_album('422866') # 传入要下载的album的id即可下载
- 配置点有:`是否使用磁盘缓存` `并发下载图片数` `图片类型转换` `下载路径` `请求元信息headers,cookies,proxies`
- **可扩展性强**
- **支持Plugin插件可以方便地扩展功能以及使用别人的插件**
- 目前内置支持的插件`登录插件``硬件占用监控插件`
- 目前内置支持的插件有:`登录插件` `硬件占用监控插件` `只下载新章插件` `压缩文件插件`
- 支持自定义本子/章节/图片下载前后的回调函数
- 支持自定义debug日志的开关/格式
- 支持自定义Downloader/Option/Client/实体类
@ -62,11 +79,15 @@ jmcomic.download_album('422866') # 传入要下载的album的id即可下载
- **多线程下载**(可细化到一图一线程,效率极高)
- 跟进了JM最新的图片分割算法2023-02-08
## 使用小说明
* Python >= 3.7
* 个人项目文档和示例会有不及时之处可以Issue提问
## 项目文件夹介绍
* assets存放一些非代码的资源文件
@ -79,6 +100,8 @@ jmcomic.download_album('422866') # 传入要下载的album的id即可下载
* tests测试目录存放测试代码使用unittest
* usage用法目录存放示例/使用代码
## 感谢以下项目
### 图片分割算法代码+禁漫移动端API

View File

@ -5,9 +5,21 @@ plugin:
- plugin: usage-log # 实时打印硬件占用率的插件
kwargs:
interval: 0.5 # 间隔时间
enable_warning: true
enable_warning: true # 占用过大时发出预警
- plugin: login # 登录插件
kwargs:
username: un
password: pw
- plugin: find_update # 只下载新章插件
kwargs:
145504: 290266 # 下载本子145504的章节290266以后的新章
after_album:
- plugin: zip # 压缩文件插件
kwargs:
level: photo # 按照章节,一个章节一个压缩文件
filename_rule: Ptitle # 压缩文件的命名规则
zip_dir: D:/GitProject/dev/pip/jmcomic/ # 压缩文件存放的文件夹
delete_original_file: true # 压缩成功后,删除所有原文件和文件夹

View File

@ -2,7 +2,7 @@
# 被依赖方 <--- 使用方
# config <--- entity <--- toolkit <--- client <--- option <--- downloader
__version__ = '2.2.1'
__version__ = '2.2.2'
from .api import *
from .jm_plugin import *

View File

@ -4,6 +4,7 @@ from .jm_downloader import *
def download_batch(download_api,
jm_id_iter: Union[Iterable, Generator],
option=None,
downloader=None,
):
"""
批量下载 album / photo
@ -12,6 +13,7 @@ def download_batch(download_api,
@param download_api: 下载api
@param jm_id_iter: jmid (album_id, photo_id) 的迭代器
@param option: 下载选项对所有的jmid使用同一个默认是 JmOption.default()
@param downloader: 下载器类
"""
from common import multi_thread_launcher
@ -23,41 +25,45 @@ def download_batch(download_api,
JmcomicText.parse_to_album_id(jmid)
for jmid in jm_id_iter
),
apply_each_obj_func=lambda aid: download_api(aid, option),
apply_each_obj_func=lambda aid: download_api(aid, option, downloader),
)
def download_album(jm_album_id, option=None):
def download_album(jm_album_id, option=None, downloader=None):
"""
下载一个本子
@param jm_album_id: 禁漫的本子的id类型可以是str/int/iterable[str]
如果是iterable[str]则会调用 download_album_batch
@param option: 下载选项为空默认是 JmOption.default()
@param downloader: 下载器类
"""
if not isinstance(jm_album_id, (str, int)):
return download_batch(download_album, jm_album_id, option)
return download_batch(download_album, jm_album_id, option, downloader)
with new_downloader(option) as dler:
with new_downloader(option, downloader) as dler:
dler.download_album(jm_album_id)
def download_photo(jm_photo_id, option=None):
def download_photo(jm_photo_id, option=None, downloader=None):
"""
下载一个章节
"""
if not isinstance(jm_photo_id, (str, int)):
return download_batch(download_photo, jm_photo_id, option)
with new_downloader(option) as dler:
with new_downloader(option, downloader) as dler:
dler.download_photo(jm_photo_id)
def new_downloader(option=None):
def new_downloader(option=None, downloader=None) -> JmDownloader:
if option is None:
option = JmModuleConfig.option_class().default()
return JmModuleConfig.downloader_class()(option)
if downloader is None:
downloader = JmModuleConfig.downloader_class()
return downloader(option)
def create_option(filepath):

View File

@ -5,6 +5,7 @@ class AbstractJmClient(
JmcomicClient,
PostmanProxy,
):
client_key: None
def __init__(self,
postman: Postman,
@ -153,6 +154,7 @@ class AbstractJmClient(
# 基于网页实现的JmClient
class JmHtmlClient(AbstractJmClient):
client_key = 'html'
def get_album_detail(self, album_id) -> JmAlbumDetail:
# 参数校验
@ -366,6 +368,7 @@ class JmHtmlClient(AbstractJmClient):
class JmApiClient(AbstractJmClient):
client_key = 'api'
API_SEARCH = '/search'
def search_album(self, search_query, main_tag=0, page=1) -> JmApiResp:
@ -437,5 +440,5 @@ class AsyncSaveImageClient(JmImageClient):
self.future_list.append(future)
JmModuleConfig.CLASS_CLIENT_IMPL['html'] = JmHtmlClient
JmModuleConfig.CLASS_CLIENT_IMPL['api'] = JmApiClient
JmModuleConfig.register_client(JmHtmlClient)
JmModuleConfig.register_client(JmApiClient)

View File

@ -297,6 +297,10 @@ class JmModuleConfig:
def register_plugin(cls, plugin_class):
cls.plugin_registry[plugin_class.plugin_key] = plugin_class
@classmethod
def register_client(cls, client_class):
cls.CLASS_CLIENT_IMPL[client_class.client_key] = client_class
jm_debug = JmModuleConfig.jm_debug
disable_jm_debug = JmModuleConfig.disable_jm_debug

View File

@ -38,7 +38,7 @@ class DownloadCallback:
def after_photo(self, photo: JmPhotoDetail):
jm_debug('photo.after',
f'章节下载完成: {photo.id} ({photo.album_id}[{photo.index}/{len(photo.from_album)}])')
f'章节下载完成: [{photo.id}] ({photo.album_id}[{photo.index}/{len(photo.from_album)}])')
def before_image(self, image: JmImageDetail, img_save_path):
if image.is_exists:
@ -65,6 +65,9 @@ class JmDownloader(DownloadCallback):
self.use_cache = self.option.download_cache
self.decode_image = self.option.download_image_decode
# 收集所有下载的image为plugin提供数据
self.all_downloaded: Dict[JmAlbumDetail, Dict[JmPhotoDetail, List[Tuple[str, JmImageDetail]]]] = {}
def download_album(self, album_id):
client = self.client_for_album(album_id)
album = client.get_album_detail(album_id)
@ -121,6 +124,9 @@ class JmDownloader(DownloadCallback):
iter_objs = self.filter_iter_objs(iter_objs)
count_real = len(iter_objs)
if count_real == 0:
return
if count_batch >= count_real:
# 一个图/章节 对应 一个线程
multi_thread_launcher(
@ -162,6 +168,34 @@ class JmDownloader(DownloadCallback):
"""
return self.option.build_jm_client()
# 下面是回调方法
def before_album(self, album: JmAlbumDetail):
super().before_album(album)
self.all_downloaded.setdefault(album, {})
def before_photo(self, photo: JmPhotoDetail):
super().before_photo(photo)
self.all_downloaded.setdefault(photo.from_album, {})
self.all_downloaded[photo.from_album].setdefault(photo, [])
def after_album(self, album: JmAlbumDetail):
super().after_album(album)
self.option.call_all_plugin(
'after_album',
album=album,
downloader=self,
)
def after_image(self, image: JmImageDetail, img_save_path):
super().after_image(image, img_save_path)
photo = image.from_photo
album = photo.from_album
self.all_downloaded.get(album).get(photo).append((img_save_path, image))
# 下面是对with语法的支持
def __enter__(self):
return self

View File

@ -14,56 +14,37 @@ class DirRule:
# 需要替换JmModuleConfig.CLASS_ALBUM / CLASS_PHOTO才能让自定义属性生效
]
RuleFunc = Callable[[Union[JmAlbumDetail, JmPhotoDetail, None]], str]
RuleSolver = List[Tuple[int, RuleFunc]]
Detail = Union[JmAlbumDetail, JmPhotoDetail, None]
RuleFunc = Callable[[Detail], str]
RuleSolver = Tuple[int, RuleFunc]
RuleSolverList = List[RuleSolver]
rule_solver_cache: Dict[Tuple[str, str], RuleSolver] = dict()
rule_solver_cache: Dict[str, RuleSolver] = {}
def __init__(self, rule, base_dir=None):
self.base_dir = self.parse_dsl(base_dir)
def __init__(self, rule: str, base_dir=None):
base_dir = self.parse_dsl(base_dir)
self.base_dir = base_dir
self.rule_dsl = rule
self.get_rule_solver()
self.solver_list = self.get_role_solver_list(rule, base_dir)
def deside_image_save_dir(self,
album: JmAlbumDetail,
photo: JmPhotoDetail,
) -> str:
def choose_param(key):
if key == 0:
return None
if key == 1:
return album
if key == 2:
return photo
solver_ls = self.get_rule_solver()
path_ls = []
for i, (key, func) in enumerate(solver_ls):
for solver in self.solver_list:
try:
param = choose_param(key)
ret = func(param)
path_ls.append(str(ret))
ret = self.apply_rule_solver(album, photo, solver)
except BaseException as e:
# noinspection PyUnboundLocalVariable
raise JmModuleConfig.exception(
f'路径规则"{self.rule_dsl}"的第{i + 1}个解析出错: {e},'
f'param is {param}'
)
jm_debug('dir_rule', f'路径规则"{self.rule_dsl}"的解析出错: {e},')
raise e
path_ls.append(str(ret))
return fix_filepath('/'.join(path_ls), is_dir=True)
def get_rule_solver(self):
key = self.rule_dsl, self.base_dir
solver_ls = self.rule_solver_cache.get(key, None)
if solver_ls is None:
solver_ls = self.solve_rule_dsl(*key)
self.rule_solver_cache[key] = solver_ls
return solver_ls
def solve_rule_dsl(self, rule_dsl: str, base_dir: str) -> RuleSolver:
def get_role_solver_list(self, rule_dsl: str, base_dir: str) -> RuleSolverList:
"""
解析下载路径dsl得到一个路径规则解析列表
"""
@ -79,18 +60,60 @@ class DirRule:
solver_ls.append((0, lambda _: base_dir))
continue
# Axxx or Pyyy
if not rule.startswith(('A', 'P')):
rule_solver = self.get_rule_solver(rule)
if rule_solver is None:
raise NotImplementedError(f'不支持的dsl: "{rule}" in "{rule_dsl}"')
key = 1 if rule[0] == 'A' else 2
solver_ls.append((
key,
lambda entity, ref=rule[1:]: fix_windir_name(str(getattr(entity, ref)))
))
solver_ls.append(rule_solver)
return solver_ls
@classmethod
def get_rule_solver(cls, rule: str) -> Optional[RuleSolver]:
# 查找缓存
if rule in cls.rule_solver_cache:
return cls.rule_solver_cache[rule]
# 检查dsl
if not rule.startswith(('A', 'P')):
return None
# Axxx or Pyyy
key = 1 if rule[0] == 'A' else 2
solve_func = lambda entity, ref=rule[1:]: fix_windir_name(str(getattr(entity, ref)))
# 保存缓存
rule_solver = (key, solve_func)
cls.rule_solver_cache[rule] = rule_solver
return rule_solver
@classmethod
def apply_rule_solver(cls, album, photo, rule_solver: RuleSolver) -> str:
"""
应用规则解析器(RuleSolver)
@param album: JmAlbumDetail
@param photo: JmPhotoDetail
@param rule_solver: Ptitle
@return: photo.title
"""
def choose_detail(key):
if key == 0:
return None
if key == 1:
return album
if key == 2:
return photo
key, func = rule_solver
detail = choose_detail(key)
return func(detail)
@classmethod
def apply_rule_directly(cls, album, photo, rule: str) -> str:
return cls.apply_rule_solver(album, photo, cls.get_rule_solver(rule))
dsl_support = {
'${workspace}': lambda text: workspace(),
}
@ -165,6 +188,27 @@ class JmOption:
mkdir_if_not_exists(save_dir)
return save_dir
def decide_album_dir(self, album: JmAlbumDetail) -> str:
"""
该方法目前仅在 plugin-zip 中使用不建议外部调用
"""
dir_layer = []
dir_rule = self.dir_rule
for rule in dir_rule.rule_dsl.split('_'):
if rule == 'Bd':
dir_layer.append(dir_rule.base_dir)
continue
if rule[0] == 'A':
name = dir_rule.apply_rule_directly(album, None, rule)
dir_layer.append(name)
if rule[0] == 'P':
break
from os.path import join
return join(*dir_layer)
def decide_image_suffix(self, image: JmImageDetail):
# 动图则使用原后缀
suffix = image.img_file_suffix
@ -298,12 +342,13 @@ class JmOption:
from .api import download_album
download_album(album_id, self)
def download_album(self, photo_id):
from .api import download_album
download_album(photo_id, self)
def download_photo(self, photo_id):
from .api import download_photo
download_photo(photo_id, self)
# 下面的方法为调用插件提供支持
def call_all_plugin(self, group: str):
def call_all_plugin(self, group: str, **extra):
plugin_list: List[dict] = self.plugin.get(group, [])
if plugin_list is None or len(plugin_list) == 0:
return
@ -319,21 +364,62 @@ class JmOption:
if plugin_class is None:
raise JmModuleConfig.exception(f'[{group}] 未注册的plugin: {key}')
self.invoke_plugin(plugin_class, kwargs)
self.invoke_plugin(plugin_class, kwargs, extra)
def invoke_plugin(self, plugin_class, kwargs: dict):
def invoke_plugin(self, plugin_class, kwargs: Any, extra: dict):
# 保证 jm_plugin.py 被加载
from .jm_plugin import JmOptionPlugin
plugin_class: Type[JmOptionPlugin]
pkey = plugin_class.plugin_key
try:
# 检查插件的参数类型
kwargs = self.fix_kwargs(kwargs)
# 把插件的配置数据kwargs和附加数据extra合并
# extra会覆盖kwargs
if len(extra) != 0:
kwargs.update(extra)
# 构建插件对象
plugin = plugin_class.build(self)
# 调用插件功能
jm_debug('plugin.invoke', f'调用插件: [{pkey}]')
plugin.invoke(**kwargs)
except JmcomicException as e:
msg = str(e)
jm_debug('plugin.exception', msg)
raise JmModuleConfig.exception(msg)
jm_debug('plugin.exception', f'插件[{pkey}]调用失败,异常信息: {msg}')
raise e
except BaseException as e:
msg = str(e)
jm_debug('plugin.error', msg)
jm_debug('plugin.error', f'插件[{pkey}]运行遇到未捕获异常,异常信息: {msg}')
raise e
# noinspection PyMethodMayBeStatic
def fix_kwargs(self, kwargs) -> Dict[str, Any]:
"""
kwargs将来要传给方法参数这要求kwargs的key是str类型
该方法检查kwargs的key的类型如果不是str尝试转为str不行则抛异常
"""
if not isinstance(kwargs, dict):
raise JmModuleConfig.exception(f'插件的kwargs参数必须为dict类型而不能是类型: {type(kwargs)}')
kwargs: dict
new_kwargs: Dict[str, Any] = {}
for k, v in kwargs.items():
if isinstance(k, str):
new_kwargs[k] = v
continue
if isinstance(k, (int, float)):
newk = str(k)
jm_debug('plugin.kwargs', f'插件参数类型转换: {k} ({type(k)}) -> {newk} ({type(newk)})')
new_kwargs[newk] = v
continue
raise JmModuleConfig.exception(
f'插件kwargs参数类型有误'
f'字段: {k}预期类型为str实际类型为{type(k)}'
)
return new_kwargs

View File

@ -2,7 +2,7 @@
该文件存放的是option扩展功能类
"""
from .jm_option import JmOption, JmModuleConfig, jm_debug
from .jm_option import *
class JmOptionPlugin:
@ -137,5 +137,158 @@ class UsageLogPlugin(JmOptionPlugin):
sleep(interval)
# 参考: https://github.com/hect0x7/JMComic-Crawler-Python/issues/95
class FindUpdatePlugin(JmOptionPlugin):
plugin_key = 'find_update'
def invoke(self, **kwargs) -> None:
self.download_album_with_find_update(kwargs or {})
def download_album_with_find_update(self, dic):
from .api import download_album
from .jm_downloader import JmDownloader
dic: Dict[str, int]
# 带入漫画id, 章节id(第x章)寻找该漫画下第x章节後的所有章节Id
def find_update(album: JmAlbumDetail):
if album.album_id not in dic:
return album
photo_ls = []
photo_begin = int(dic[album.album_id])
is_new_photo = False
for photo in album:
if is_new_photo:
photo_ls.append(photo)
if int(photo.photo_id) == photo_begin:
is_new_photo = True
return photo_ls
class FindUpdateDownloader(JmDownloader):
def filter_iter_objs(self, iter_objs):
if not isinstance(iter_objs, JmAlbumDetail):
return iter_objs
return find_update(iter_objs)
# 调用下载api指定option和downloader
download_album(
jm_album_id=dic.keys(),
option=self.option,
downloader=FindUpdateDownloader,
)
class ZipPlugin(JmOptionPlugin):
plugin_key = 'zip'
def invoke(self,
album: JmAlbumDetail,
downloader,
delete_original_file=False,
level='photo',
filename_rule='Ptitle',
suffix='zip',
zip_dir='./'
) -> None:
from .jm_downloader import JmDownloader
downloader: JmDownloader
mkdir_if_not_exists(zip_dir)
photo_dict = downloader.all_downloaded[album]
original_file_dir_list = []
if level == 'album':
zip_path = self.get_zip_path(album, None, filename_rule, suffix, zip_dir)
original_file_dir_list.append(
self.zip_album(album, photo_dict, zip_path)
)
elif level == 'photo':
# dst_file_list = []
for photo, image_list in photo_dict.items():
zip_path = self.get_zip_path(None, photo, filename_rule, suffix, zip_dir)
original_file_dir_list.append(
self.zip_photo(photo, image_list, zip_path)
)
# dst_file_list.append(zip_path)
else:
raise NotImplementedError(f'level: {level}')
if delete_original_file is True:
self.delete_all_files(downloader.all_downloaded, original_file_dir_list)
# noinspection PyMethodMayBeStatic
def delete_all_files(self, all_downloaded: dict, dir_list: List[str]):
import os
for album, photo_dict in all_downloaded.items():
for photo, image_list in photo_dict.items():
for f, image in image_list:
os.remove(f)
jm_debug('plugin.zip.remove', f'移除原文件: {f}')
for d in dir_list:
if len(files_of_dir(d)) == 0:
os.removedirs(d)
jm_debug('plugin.zip.remove', f'移除文件夹: {d}')
def zip_photo(self, photo, image_list: list, zip_path: str):
photo_dir = self.option.decide_image_save_dir(photo) \
if len(image_list) == 0 \
else os.path.dirname(image_list[0][0])
all_filepath = set(map(lambda t: t[0], image_list))
if len(all_filepath) == 0:
jm_debug('plugin.zip.skip', '无下载文件,无需压缩')
return
from common import backup_dir_to_zip
backup_dir_to_zip(photo_dir, zip_path, acceptor=lambda f: f in all_filepath)
jm_debug('plugin.zip.finish', f'压缩章节[{photo.photo_id}]成功 → {zip_path}')
return photo_dir
def zip_album(self, album, photo_dict: dict, zip_path):
album_dir = self.option.decide_album_dir(album)
all_filepath: Set[str] = set()
for image_list in photo_dict.values():
image_list: List[Tuple[str, JmImageDetail]]
for path, _ in image_list:
all_filepath.add(path)
if len(all_filepath) == 0:
jm_debug('plugin.zip.skip', '无下载文件,无需压缩')
return
from common import backup_dir_to_zip
backup_dir_to_zip(
album_dir,
zip_path,
acceptor=lambda f: f in all_filepath
)
jm_debug('plugin.zip.finish', f'压缩本子[{album.album_id}]成功 → {zip_path}')
return album_dir
# noinspection PyMethodMayBeStatic
def get_zip_path(self, album, photo, filename_rule, suffix, zip_dir):
filename = DirRule.apply_rule_directly(album, photo, filename_rule)
from os.path import join
return join(
zip_dir,
filename + fix_suffix(suffix),
)
JmModuleConfig.register_plugin(JmLoginPlugin)
JmModuleConfig.register_plugin(UsageLogPlugin)
JmModuleConfig.register_plugin(FindUpdatePlugin)
JmModuleConfig.register_plugin(ZipPlugin)

View File

@ -7,6 +7,12 @@ from jmcomic import *
option = JmOption.default()
meta_data = {
# 'proxies': ProxyBuilder.clash_proxy()
}
disable_jm_debug()
def get_domain_ls():
template = 'https://jmcmomic.github.io/go/{}.html'
@ -17,9 +23,12 @@ def get_domain_ls():
domain_set: Set[str] = set()
def fetch_domain(url):
postman = JmModuleConfig.new_postman()
text = postman.get(url, allow_redirects=False).text
# from curl_cffi import requests as postman
postman = CurlCffiPostman.create()
text = postman.get(url, allow_redirects=False, **meta_data).text
for domain in JmcomicText.analyse_jm_pub_html(text):
if domain.startswith('jm365.work'):
continue
domain_set.add(domain)
multi_thread_launcher(
@ -31,10 +40,11 @@ def get_domain_ls():
domain_set = get_domain_ls()
domain_status_dict = {}
print(f'获取到{len(domain_set)}个域名,开始测试')
def test_domain(domain: str):
client = option.new_jm_client(domain_list=[domain])
client = option.new_jm_client(domain_list=[domain], **meta_data)
status = 'ok'
try:

200
usage/usage_advanced.py Normal file
View File

@ -0,0 +1,200 @@
"""
jmcomic综合使用实例基于v2.2.2+内置插件
功能需求
1. 下载id为145504的本子
2. 只下载章节在290266之后的新章
3. 最后要把图片转为jpg格式
4. 要使用登录状态去下载
5. 压缩文件按照章节压缩一个章节一个压缩文件压缩文件的命名: 章节标题.zip
6. 自动把下载的文件全部删除最后只要保留压缩文件
实现方案
1. 写2行python代码
2. 配置option调用1的脚本即可
"""
# 1. 写2行python代码
from jmcomic import create_option
create_option('myoption.yml')
# 2. 配置option调用1的脚本即可
"""
dir_rule: # 下载路径规则
rule: Bd_Aid
base_dir: D:/jmcomic
download:
image:
suffix: .jpg # 转为jpg格式的图片
client:
domain:
- 18comic.vip # 指定域名
plugin:
after_init:
- plugin: login # 登录插件
kwargs:
username: un
password: pw
- plugin: find_update # 只下载新章插件
kwargs:
145504: 290266 # 下载本子145504的章节290266以后的新章
after_album:
- plugin: zip # 压缩文件插件
kwargs:
level: photo # 按照章节,一个章节一个压缩文件
filename_rule: Ptitle # 压缩文件的命名规则
zip_dir: D:/GitProject/dev/pip/jmcomic/ # 压缩文件存放的文件夹
delete_original_file: true # 压缩成功后,删除所有原文件和文件夹
"""
# 到此,程序已开始运行,最后会完成所有需求,并打印出如下日志。
# 你可以详细查看以下日志,运行时所有关键节点都有日志打印。
"""
2023-08-01 02:23:57:plugin.invoke调用插件: [login]
2023-08-01 02:23:57:htmlhttps://18comic.vip/login
2023-08-01 02:23:58:plugin.login登录成功
2023-08-01 02:23:58:plugin.kwargs插件参数类型转换: 145504 (<class 'int'>) -> 145504 (<class 'str'>)
2023-08-01 02:23:58:plugin.invoke调用插件: [find_update]
2023-08-01 02:23:58:htmlhttps://18comic.vip/album/145504
2023-08-01 02:23:59:album.before本子获取成功: [145504], 作者: [G.HO], 章节数: [104], 总页数: [3598], 标题: [健身教练 / もしも幼馴染を抱いたなら / Fitness], 关键词: [['完結', '韩漫', '上柱香再走', '以晨:我爹呢', '你妈真香', '連載中', '肌肉豪名不虚传']], 2023-08-01 02:23:59:htmlhttps://18comic.vip/photo/291640
2023-08-01 02:24:00:photo.before开始下载章节: 291640 (145504[104/104]), 标题: [健身教练 完結], 图片数为[41]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00001.webp [1/41], [https://cdn-msp.18comic.vip/media/photos/291640/00001.webp] [D:/jmcomic/145504/00001.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00004.webp [4/41], [https://cdn-msp.18comic.vip/media/photos/291640/00004.webp] [D:/jmcomic/145504/00004.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00003.webp [3/41], [https://cdn-msp.18comic.vip/media/photos/291640/00003.webp] [D:/jmcomic/145504/00003.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00007.webp [7/41], [https://cdn-msp.18comic.vip/media/photos/291640/00007.webp] [D:/jmcomic/145504/00007.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00005.webp [5/41], [https://cdn-msp.18comic.vip/media/photos/291640/00005.webp] [D:/jmcomic/145504/00005.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00002.webp [2/41], [https://cdn-msp.18comic.vip/media/photos/291640/00002.webp] [D:/jmcomic/145504/00002.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00008.webp [8/41], [https://cdn-msp.18comic.vip/media/photos/291640/00008.webp] [D:/jmcomic/145504/00008.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00006.webp [6/41], [https://cdn-msp.18comic.vip/media/photos/291640/00006.webp] [D:/jmcomic/145504/00006.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00009.webp [9/41], [https://cdn-msp.18comic.vip/media/photos/291640/00009.webp] [D:/jmcomic/145504/00009.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00010.webp [10/41], [https://cdn-msp.18comic.vip/media/photos/291640/00010.webp] [D:/jmcomic/145504/00010.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00011.webp [11/41], [https://cdn-msp.18comic.vip/media/photos/291640/00011.webp] [D:/jmcomic/145504/00011.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00012.webp [12/41], [https://cdn-msp.18comic.vip/media/photos/291640/00012.webp] [D:/jmcomic/145504/00012.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00013.webp [13/41], [https://cdn-msp.18comic.vip/media/photos/291640/00013.webp] [D:/jmcomic/145504/00013.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00014.webp [14/41], [https://cdn-msp.18comic.vip/media/photos/291640/00014.webp] [D:/jmcomic/145504/00014.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00015.webp [15/41], [https://cdn-msp.18comic.vip/media/photos/291640/00015.webp] [D:/jmcomic/145504/00015.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00016.webp [16/41], [https://cdn-msp.18comic.vip/media/photos/291640/00016.webp] [D:/jmcomic/145504/00016.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00017.webp [17/41], [https://cdn-msp.18comic.vip/media/photos/291640/00017.webp] [D:/jmcomic/145504/00017.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00018.webp [18/41], [https://cdn-msp.18comic.vip/media/photos/291640/00018.webp] [D:/jmcomic/145504/00018.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00019.webp [19/41], [https://cdn-msp.18comic.vip/media/photos/291640/00019.webp] [D:/jmcomic/145504/00019.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00020.webp [20/41], [https://cdn-msp.18comic.vip/media/photos/291640/00020.webp] [D:/jmcomic/145504/00020.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00021.webp [21/41], [https://cdn-msp.18comic.vip/media/photos/291640/00021.webp] [D:/jmcomic/145504/00021.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00023.webp [23/41], [https://cdn-msp.18comic.vip/media/photos/291640/00023.webp] [D:/jmcomic/145504/00023.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00022.webp [22/41], [https://cdn-msp.18comic.vip/media/photos/291640/00022.webp] [D:/jmcomic/145504/00022.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00024.webp [24/41], [https://cdn-msp.18comic.vip/media/photos/291640/00024.webp] [D:/jmcomic/145504/00024.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00025.webp [25/41], [https://cdn-msp.18comic.vip/media/photos/291640/00025.webp] [D:/jmcomic/145504/00025.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00027.webp [27/41], [https://cdn-msp.18comic.vip/media/photos/291640/00027.webp] [D:/jmcomic/145504/00027.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00026.webp [26/41], [https://cdn-msp.18comic.vip/media/photos/291640/00026.webp] [D:/jmcomic/145504/00026.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00028.webp [28/41], [https://cdn-msp.18comic.vip/media/photos/291640/00028.webp] [D:/jmcomic/145504/00028.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00029.webp [29/41], [https://cdn-msp.18comic.vip/media/photos/291640/00029.webp] [D:/jmcomic/145504/00029.jpg]
2023-08-01 02:24:00:image.before图片准备下载: 291640/00030.webp [30/41], [https://cdn-msp.18comic.vip/media/photos/291640/00030.webp] [D:/jmcomic/145504/00030.jpg]
2023-08-01 02:24:01:image.after图片下载完成: 291640/00017.webp [17/41], [https://cdn-msp.18comic.vip/media/photos/291640/00017.webp] [D:/jmcomic/145504/00017.jpg]
2023-08-01 02:24:01:image.before图片准备下载: 291640/00031.webp [31/41], [https://cdn-msp.18comic.vip/media/photos/291640/00031.webp] [D:/jmcomic/145504/00031.jpg]
2023-08-01 02:24:01:image.after图片下载完成: 291640/00007.webp [7/41], [https://cdn-msp.18comic.vip/media/photos/291640/00007.webp] [D:/jmcomic/145504/00007.jpg]
2023-08-01 02:24:01:image.before图片准备下载: 291640/00032.webp [32/41], [https://cdn-msp.18comic.vip/media/photos/291640/00032.webp] [D:/jmcomic/145504/00032.jpg]
2023-08-01 02:24:01:image.after图片下载完成: 291640/00021.webp [21/41], [https://cdn-msp.18comic.vip/media/photos/291640/00021.webp] [D:/jmcomic/145504/00021.jpg]
2023-08-01 02:24:01:image.before图片准备下载: 291640/00033.webp [33/41], [https://cdn-msp.18comic.vip/media/photos/291640/00033.webp] [D:/jmcomic/145504/00033.jpg]
2023-08-01 02:24:02:image.after图片下载完成: 291640/00003.webp [3/41], [https://cdn-msp.18comic.vip/media/photos/291640/00003.webp] [D:/jmcomic/145504/00003.jpg]
2023-08-01 02:24:02:image.before图片准备下载: 291640/00034.webp [34/41], [https://cdn-msp.18comic.vip/media/photos/291640/00034.webp] [D:/jmcomic/145504/00034.jpg]
2023-08-01 02:24:03:image.after图片下载完成: 291640/00008.webp [8/41], [https://cdn-msp.18comic.vip/media/photos/291640/00008.webp] [D:/jmcomic/145504/00008.jpg]
2023-08-01 02:24:03:image.before图片准备下载: 291640/00035.webp [35/41], [https://cdn-msp.18comic.vip/media/photos/291640/00035.webp] [D:/jmcomic/145504/00035.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00015.webp [15/41], [https://cdn-msp.18comic.vip/media/photos/291640/00015.webp] [D:/jmcomic/145504/00015.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00036.webp [36/41], [https://cdn-msp.18comic.vip/media/photos/291640/00036.webp] [D:/jmcomic/145504/00036.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00029.webp [29/41], [https://cdn-msp.18comic.vip/media/photos/291640/00029.webp] [D:/jmcomic/145504/00029.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00030.webp [30/41], [https://cdn-msp.18comic.vip/media/photos/291640/00030.webp] [D:/jmcomic/145504/00030.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00037.webp [37/41], [https://cdn-msp.18comic.vip/media/photos/291640/00037.webp] [D:/jmcomic/145504/00037.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00038.webp [38/41], [https://cdn-msp.18comic.vip/media/photos/291640/00038.webp] [D:/jmcomic/145504/00038.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00019.webp [19/41], [https://cdn-msp.18comic.vip/media/photos/291640/00019.webp] [D:/jmcomic/145504/00019.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00039.webp [39/41], [https://cdn-msp.18comic.vip/media/photos/291640/00039.webp] [D:/jmcomic/145504/00039.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00024.webp [24/41], [https://cdn-msp.18comic.vip/media/photos/291640/00024.webp] [D:/jmcomic/145504/00024.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00040.webp [40/41], [https://cdn-msp.18comic.vip/media/photos/291640/00040.webp] [D:/jmcomic/145504/00040.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00026.webp [26/41], [https://cdn-msp.18comic.vip/media/photos/291640/00026.webp] [D:/jmcomic/145504/00026.jpg]
2023-08-01 02:24:04:image.before图片准备下载: 291640/00041.webp [41/41], [https://cdn-msp.18comic.vip/media/photos/291640/00041.webp] [D:/jmcomic/145504/00041.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00001.webp [1/41], [https://cdn-msp.18comic.vip/media/photos/291640/00001.webp] [D:/jmcomic/145504/00001.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00010.webp [10/41], [https://cdn-msp.18comic.vip/media/photos/291640/00010.webp] [D:/jmcomic/145504/00010.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00012.webp [12/41], [https://cdn-msp.18comic.vip/media/photos/291640/00012.webp] [D:/jmcomic/145504/00012.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00032.webp [32/41], [https://cdn-msp.18comic.vip/media/photos/291640/00032.webp] [D:/jmcomic/145504/00032.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00011.webp [11/41], [https://cdn-msp.18comic.vip/media/photos/291640/00011.webp] [D:/jmcomic/145504/00011.jpg]
2023-08-01 02:24:04:image.after图片下载完成: 291640/00034.webp [34/41], [https://cdn-msp.18comic.vip/media/photos/291640/00034.webp] [D:/jmcomic/145504/00034.jpg]
2023-08-01 02:24:05:image.after图片下载完成: 291640/00023.webp [23/41], [https://cdn-msp.18comic.vip/media/photos/291640/00023.webp] [D:/jmcomic/145504/00023.jpg]
2023-08-01 02:24:05:image.after图片下载完成: 291640/00002.webp [2/41], [https://cdn-msp.18comic.vip/media/photos/291640/00002.webp] [D:/jmcomic/145504/00002.jpg]
2023-08-01 02:24:05:image.after图片下载完成: 291640/00038.webp [38/41], [https://cdn-msp.18comic.vip/media/photos/291640/00038.webp] [D:/jmcomic/145504/00038.jpg]
2023-08-01 02:24:05:image.after图片下载完成: 291640/00041.webp [41/41], [https://cdn-msp.18comic.vip/media/photos/291640/00041.webp] [D:/jmcomic/145504/00041.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00035.webp [35/41], [https://cdn-msp.18comic.vip/media/photos/291640/00035.webp] [D:/jmcomic/145504/00035.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00009.webp [9/41], [https://cdn-msp.18comic.vip/media/photos/291640/00009.webp] [D:/jmcomic/145504/00009.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00031.webp [31/41], [https://cdn-msp.18comic.vip/media/photos/291640/00031.webp] [D:/jmcomic/145504/00031.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00033.webp [33/41], [https://cdn-msp.18comic.vip/media/photos/291640/00033.webp] [D:/jmcomic/145504/00033.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00027.webp [27/41], [https://cdn-msp.18comic.vip/media/photos/291640/00027.webp] [D:/jmcomic/145504/00027.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00039.webp [39/41], [https://cdn-msp.18comic.vip/media/photos/291640/00039.webp] [D:/jmcomic/145504/00039.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00036.webp [36/41], [https://cdn-msp.18comic.vip/media/photos/291640/00036.webp] [D:/jmcomic/145504/00036.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00020.webp [20/41], [https://cdn-msp.18comic.vip/media/photos/291640/00020.webp] [D:/jmcomic/145504/00020.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00037.webp [37/41], [https://cdn-msp.18comic.vip/media/photos/291640/00037.webp] [D:/jmcomic/145504/00037.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00040.webp [40/41], [https://cdn-msp.18comic.vip/media/photos/291640/00040.webp] [D:/jmcomic/145504/00040.jpg]
2023-08-01 02:24:06:image.after图片下载完成: 291640/00004.webp [4/41], [https://cdn-msp.18comic.vip/media/photos/291640/00004.webp] [D:/jmcomic/145504/00004.jpg]
2023-08-01 02:24:07:image.after图片下载完成: 291640/00005.webp [5/41], [https://cdn-msp.18comic.vip/media/photos/291640/00005.webp] [D:/jmcomic/145504/00005.jpg]
2023-08-01 02:24:07:image.after图片下载完成: 291640/00025.webp [25/41], [https://cdn-msp.18comic.vip/media/photos/291640/00025.webp] [D:/jmcomic/145504/00025.jpg]
2023-08-01 02:24:07:image.after图片下载完成: 291640/00014.webp [14/41], [https://cdn-msp.18comic.vip/media/photos/291640/00014.webp] [D:/jmcomic/145504/00014.jpg]
2023-08-01 02:24:07:image.after图片下载完成: 291640/00028.webp [28/41], [https://cdn-msp.18comic.vip/media/photos/291640/00028.webp] [D:/jmcomic/145504/00028.jpg]
2023-08-01 02:24:07:image.after图片下载完成: 291640/00018.webp [18/41], [https://cdn-msp.18comic.vip/media/photos/291640/00018.webp] [D:/jmcomic/145504/00018.jpg]
2023-08-01 02:24:08:image.after图片下载完成: 291640/00022.webp [22/41], [https://cdn-msp.18comic.vip/media/photos/291640/00022.webp] [D:/jmcomic/145504/00022.jpg]
2023-08-01 02:24:08:image.after图片下载完成: 291640/00016.webp [16/41], [https://cdn-msp.18comic.vip/media/photos/291640/00016.webp] [D:/jmcomic/145504/00016.jpg]
2023-08-01 02:24:08:image.after图片下载完成: 291640/00006.webp [6/41], [https://cdn-msp.18comic.vip/media/photos/291640/00006.webp] [D:/jmcomic/145504/00006.jpg]
2023-08-01 02:24:08:image.after图片下载完成: 291640/00013.webp [13/41], [https://cdn-msp.18comic.vip/media/photos/291640/00013.webp] [D:/jmcomic/145504/00013.jpg]
2023-08-01 02:24:08:photo.after章节下载完成: [291640] (145504[104/104])
2023-08-01 02:24:08:album.after本子下载完成: [145504]
2023-08-01 02:24:08:plugin.invoke调用插件: [zip]
2023-08-01 02:24:08:plugin.zip.finish压缩章节[291640]成功 D:/GitProject/dev/pip/jmcomic/健身教练 完結.zip
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00017.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00007.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00021.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00003.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00008.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00015.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00029.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00030.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00019.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00024.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00026.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00001.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00010.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00012.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00032.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00011.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00034.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00023.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00002.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00038.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00041.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00035.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00009.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00031.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00033.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00027.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00039.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00036.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00020.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00037.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00040.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00004.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00005.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00025.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00014.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00028.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00018.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00022.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00016.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00006.jpg
2023-08-01 02:24:08:plugin.zip.remove移除原文件: D:/jmcomic/145504/00013.jpg
2023-08-01 02:24:08:plugin.zip.remove移除文件夹: D:/jmcomic/145504
进程已结束退出代码为 0
"""

View File

@ -1,6 +1,5 @@
"""
本文件演示 jmcomic 的filter过滤器
filter(过滤器)是v2.1.12新引入的机制
利用filter你可以实现下载时过滤本子/章节/图片完全控制你要下载的内容
使用filter的步骤如下

View File

@ -1,11 +1,13 @@
"""
plugin(扩展/插件)jmcomic=2.2.0新引入的机制
plugin(扩展/插件)v2.2.0新引入的机制
plugin机制可以实现在`特定时间` 回调 `特定插件`实现灵活无感知的功能增强
目前仅支持一个时机: after_init表示在option对象的 __init__ 初始化方法的最后
下面以内置插件[login]为例
插件功能登录JM获取并保存cookies
你可以在option配置文件当中配置如下内容来实现在 after_init 时机调用login插件
下面举例演示
特定时间after_init
特定插件login
插件功能登录JM获取并保存cookies所有的Client都会使用这个cookies
你可以在option配置文件当中配置如下内容来实现在after_init时调用login插件
plugin:
after_init: # 时机
@ -15,6 +17,18 @@ plugin:
username: un # 禁漫帐号
password: pw # 密码
有了上述option配置当你调用下面的代码时login插件就会执行
import jmcomic
option = jmcomic.create_option('xxx.yml')
# 程序走到这里login插件已经调用完毕了。
-----------------------------------------
目前jmcomic已经内置了一些强大的插件源码位于 src/jmcomic/jm_plugin.py
配置插件的方式请查看 assets/config/option_plugin
-----------------------------------------
你也可以自定义插件和插件时机
自定义插件时机需要你重写Option类示例请见 usage_custom
下面演示自定义插件分为3步: