From ac33f4d4ca3578095e0720c22ea5e7e906364a85 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 29 Apr 2024 23:13:56 +0800 Subject: [PATCH] =?UTF-8?q?v2.5.11:=20=E6=96=B0=E5=A2=9E=E3=80=90img2pdf?= =?UTF-8?q?=E3=80=91=E6=8F=92=E4=BB=B6=E5=AE=9E=E7=8E=B0=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E4=B8=BApdf=EF=BC=8C=E5=8F=AF=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=E6=97=A7=E7=9A=84=E3=80=90j2p=E3=80=91=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=8A=9F=E8=83=BD=E6=9B=B4=E5=8A=A0=E5=BC=BA?= =?UTF-8?q?=E5=A4=A7;=20=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3;=20(#230)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/docs/sources/TODO.md | 2 +- assets/docs/sources/option_file_syntax.md | 34 ++++++++++++------ src/jmcomic/__init__.py | 2 +- src/jmcomic/jm_client_interface.py | 12 +++++++ src/jmcomic/jm_plugin.py | 43 +++++++++++++++++++++++ tests/test_jmcomic/test_jm_api.py | 5 ++- tests/test_jmcomic/test_jm_custom.py | 5 ++- 7 files changed, 88 insertions(+), 15 deletions(-) diff --git a/assets/docs/sources/TODO.md b/assets/docs/sources/TODO.md index 9f57ecf2..94d640f6 100644 --- a/assets/docs/sources/TODO.md +++ b/assets/docs/sources/TODO.md @@ -1,4 +1,4 @@ -# Plan For Update Content +# 版本更新计划 | 版本范围 | 更新计划 | |:--------:|:--------------------------------------:| diff --git a/assets/docs/sources/option_file_syntax.md b/assets/docs/sources/option_file_syntax.md index 611a0653..a7be1762 100644 --- a/assets/docs/sources/option_file_syntax.md +++ b/assets/docs/sources/option_file_syntax.md @@ -1,13 +1,12 @@ -# Option File Syntax +# 配置文件指南 ## 1. 配置前需知 * option有`默认值`,当你使用配置文件来创建option时,你配置文件中的值会覆盖`默认值`。 因此,在配置option时,不需要配置全部的值,只需要配置特定部分即可。 -* 你可以使用下面的代码来得到option的默认值,你可以删除其中的大部分配置项,只保留你要覆盖的配置项 -* **下面的插件配置,kwargs参数支持引用环境变量,语法为 ${环境变量名}** +* 你可以使用下面的代码来得到option的默认值,你可以删除其中的大部分配置项,只保留你要覆盖的配置项 ```python from jmcomic import JmOption @@ -17,8 +16,8 @@ JmOption.default().to_file('./option.yml') # 创建默认option,导出为optio ## 2. option常规配置项 ```yml -# 开启jmcomic的日志输入,默认为true -# 对日志有需求的可进一步参考文档 +# 开启jmcomic的日志输出,默认为true +# 对日志有需求的可进一步参考文档 → https://jmcomic.readthedocs.io/en/latest/tutorial/11_log_custom/ log: true # 配置客户端相关 @@ -26,7 +25,7 @@ client: # impl: 客户端实现类,不配置默认会使用JmModuleConfig.DEFAULT_CLIENT_IMPL # 可配置: # html - 表示网页端 - # api - 表示使用APP端 + # api - 表示APP端 impl: html # domain: 域名配置,默认是 [],表示运行时自动获取域名。 @@ -43,7 +42,7 @@ client: # postman: 请求配置 postman: - meta_data: + metadata: # proxies: 代理配置,默认是 system,表示使用系统代理。 # 以下的写法都可以: # proxies: null # 不使用代理 @@ -108,6 +107,8 @@ dir_rule: ## 3. option插件配置项 +* **插件配置中的kwargs参数支持引用环境变量,语法为 ${环境变量名}** + ```yml # 插件的配置示例 plugins: @@ -136,14 +137,14 @@ plugins: proxy_client_key: photo_concurrent_fetcher_proxy # 代理类的client_key whitelist: [ api, ] # 白名单,当client.impl匹配白名单时才代理 - - plugin: auto_set_browser_cookies # 自动获取浏览器cookies,详见插件类 + - plugin: auto_set_browser_cookies # 自动获取浏览器cookies,详见插件类代码→AutoSetBrowserCookiesPlugin kwargs: browser: chrome domain: 18comic.vip # v2.5.0 引入的插件 # 可以启动一个服务器,可以在浏览器上查看本子 - # 基于flask框架,需要安装额外库: pip install plugin_jm_server + # 基于flask框架,需要安装额外库: [pip install plugin_jm_server] # 源码:https://github.com/hect0x7/plugin-jm-server - plugin: jm_server kwargs: @@ -212,6 +213,17 @@ plugins: at_least_image_count: 3 # 至少要有多少张图,才下载此章节 after_photo: + # 把章节的所有图片合并为一个pdf的插件 + # 使用前需要安装依赖库: [pip install img2pdf] + - plugin: img2pdf + kwargs: + pdf_dir: D:/pdf/ # pdf存放文件夹 + filename_rule: Pid # pdf命名规则 + + # 请注意⚠ + # 下方的j2p插件的功能不如img2pdf插件,不建议使用。 + # 如有图片转pdf的需求,直接使用img2pdf即可,下面的内容请忽略。 + - plugin: j2p # 图片合并插件,可以将下载下来的jpg图片合成为一个pdf插件 # 请注意⚠ 该插件的使用前提是,下载下来的图片是jpg图片 # 因此,使用该插件前,需要有如下配置:(下载图片格式转为jpg,上文有解释过此配置) @@ -219,8 +231,8 @@ plugins: # image: # suffix: .jpg kwargs: - pdf_dir: D:/pdf # pdf存放文件夹 + pdf_dir: D:/pdf/ # pdf存放文件夹 filename_rule: Pid # pdf命名规则 quality: 100 # pdf质量,0 - 100 - + ``` diff --git a/src/jmcomic/__init__.py b/src/jmcomic/__init__.py index ad68fc8c..c43f17a7 100644 --- a/src/jmcomic/__init__.py +++ b/src/jmcomic/__init__.py @@ -2,7 +2,7 @@ # 被依赖方 <--- 使用方 # config <--- entity <--- toolkit <--- client <--- option <--- downloader -__version__ = '2.5.10' +__version__ = '2.5.11' from .api import * from .jm_plugin import * diff --git a/src/jmcomic/jm_client_interface.py b/src/jmcomic/jm_client_interface.py index a641e747..dcdfa03f 100644 --- a/src/jmcomic/jm_client_interface.py +++ b/src/jmcomic/jm_client_interface.py @@ -572,3 +572,15 @@ def categories_filter_gen(self, } yield from self.do_page_iter(params, page, self.categories_filter) + + def is_given_type(self, ctype: Type['JmcomicClient']) -> bool: + """ + Client代理的此方法会被路由到内部client的方法 + 即:ClientProxy(AClient()).is_given_type(AClient) is True + 但是: ClientProxy(AClient()).client_key != AClient.client_key + """ + if isinstance(self, ctype): + return True + if self.client_key == instance.client_key: + return True + return False diff --git a/src/jmcomic/jm_plugin.py b/src/jmcomic/jm_plugin.py index bcf57f92..29081c9e 100644 --- a/src/jmcomic/jm_plugin.py +++ b/src/jmcomic/jm_plugin.py @@ -757,6 +757,49 @@ def generate_cmd(): self.execute_deletion(paths) +class Img2pdfPlugin(JmOptionPlugin): + plugin_key = 'img2pdf' + + def invoke(self, + photo: JmPhotoDetail, + downloader=None, + pdf_dir=None, + filename_rule='Pid', + delete_original_file=False, + **kwargs, + ): + try: + import img2pdf + except ImportError: + self.warning_lib_not_install('img2pdf') + return + + self.delete_original_file = delete_original_file + + # 处理文件夹配置 + filename = DirRule.apply_rule_directly(None, photo, filename_rule) + photo_dir = self.option.decide_image_save_dir(photo) + + # 处理生成的pdf文件的路径 + if pdf_dir is None: + pdf_dir = photo_dir + else: + pdf_dir = fix_filepath(pdf_dir, True) + mkdir_if_not_exists(pdf_dir) + + pdf_filepath = os.path.join(pdf_dir, f'{filename}.pdf') + + # 调用 img2pdf 把 photo_dir 下的所有图片转为pdf + all_img = files_of_dir(photo_dir) + with open(pdf_filepath, 'wb') as f: + f.write(img2pdf.convert(all_img)) + + # 执行删除 + self.log(f'Convert Successfully: JM{photo.id} → {pdf_filepath}') + all_img.append(self.option.decide_image_save_dir(photo, ensure_exists=False)) + self.execute_deletion(all_img) + + class JmServerPlugin(JmOptionPlugin): plugin_key = 'jm_server' diff --git a/tests/test_jmcomic/test_jm_api.py b/tests/test_jmcomic/test_jm_api.py index 1c551c0a..226d5aad 100644 --- a/tests/test_jmcomic/test_jm_api.py +++ b/tests/test_jmcomic/test_jm_api.py @@ -69,7 +69,10 @@ def run_func_async(func): if len(exception_list) == 0: return + if self.client.is_given_type(JmApiClient): + return + for e in exception_list: print(e) - # raise AssertionError(exception_list) + raise AssertionError(exception_list) diff --git a/tests/test_jmcomic/test_jm_custom.py b/tests/test_jmcomic/test_jm_custom.py index 1b6372f8..a61354a5 100644 --- a/tests/test_jmcomic/test_jm_custom.py +++ b/tests/test_jmcomic/test_jm_custom.py @@ -60,7 +60,10 @@ class MyClient(JmHtmlClient): # 2024-04-29 # 禁漫的【永久網域】加了cf,GitHub Actions请求也会失败。 traceback_print_exec() - return + if self.client.is_given_type(JmApiClient): + return + else: + raise e JmModuleConfig.DOMAIN_HTML_LIST = [html_domain]