From 950a4776570ce222a2ca1bba15f9b12a39e9aff7 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:17:35 +0800 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20=E6=8E=A5=E5=85=A5=20Python=20log?= =?UTF-8?q?ging=20=E5=B9=B6=E9=87=8D=E6=9E=84=E8=A7=84=E8=8C=83=20jm=5Flog?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=20ExceptionListener=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/docs/sources/tutorial/11_log_custom.md | 6 +++- .../docs/sources/tutorial/4_module_custom.md | 28 +++++++++------ src/jmcomic/__init__.py | 2 +- src/jmcomic/jm_config.py | 35 +++++++++++++++---- src/jmcomic/jm_exception.py | 1 + src/jmcomic/jm_option.py | 2 +- src/jmcomic/jm_plugin.py | 22 ++++++------ 7 files changed, 67 insertions(+), 29 deletions(-) diff --git a/assets/docs/sources/tutorial/11_log_custom.md b/assets/docs/sources/tutorial/11_log_custom.md index f1a971d12..b3a226270 100644 --- a/assets/docs/sources/tutorial/11_log_custom.md +++ b/assets/docs/sources/tutorial/11_log_custom.md @@ -8,9 +8,13 @@ 使用代码: -``` +```python from jmcomic import disable_jm_log disable_jm_log() + +# 推荐使用 Python 原生的 logging 控制 +import logging +logging.getLogger("jmcomic").setLevel(logging.WARNING) # 只显示警告以上的日志 ``` 使用配置: diff --git a/assets/docs/sources/tutorial/4_module_custom.md b/assets/docs/sources/tutorial/4_module_custom.md index 2f16013a2..bde8c4139 100644 --- a/assets/docs/sources/tutorial/4_module_custom.md +++ b/assets/docs/sources/tutorial/4_module_custom.md @@ -137,24 +137,32 @@ def custom_album_photo_image_detail_class(): ```python def custom_jm_log(): """ - 该函数演示自定义log + 该函数演示如何接管和自定义日志输出 """ - # jmcomic模块在运行过程中会使用 jm_log() 这个函数进行打印信息 - # jm_log() 这个函数 最后会调用 JmModuleConfig.EXECUTOR_LOG 函数 - # 你可以写一个自己的函数,替换 JmModuleConfig.EXECUTOR_LOG,实现自定义log + # jmcomic 项目默认使用内置的 Python logging 模块 + # 其日志记录器的名字固定为 "jmcomic" - # 1. 自定义log函数 - def my_log(topic: str, msg: str): + # 【推荐方式】直接配置原生的 logging logger + import logging + jm_logger = logging.getLogger("jmcomic") + + # 例如,取消默认往下游控制台打印的 Handler,转存到文件中 + jm_logger.handlers.clear() + jm_logger.addHandler(logging.FileHandler("jm_download.log", encoding="utf-8")) + + # 【向后兼容方式/遗留用法】 + # 你依然可以通过替换全局配置类的 EXECUTOR_LOG 函数暴力接管日志 + def my_custom_log(topic: str, msg, e: Exception = None): """ - 这个log函数的参数列表必须包含两个参数,topic和msg @param topic: log主题,例如 'album.before', 'req.error', 'plugin.error' - @param msg: 具体log的信息 + @param msg: 具体log的信息,也可以直接传入 Exception 对象(底层会自动适配) + @param e: 可选,异常对象(当 msg 本身就是 Exception 时无需传) """ pass - # 2. 让my_log生效 - JmModuleConfig.EXECUTOR_LOG = my_log + # 生效自定义的 proxy + JmModuleConfig.EXECUTOR_LOG = my_custom_log ``` diff --git a/src/jmcomic/__init__.py b/src/jmcomic/__init__.py index 7f6f32172..10c7d0205 100644 --- a/src/jmcomic/__init__.py +++ b/src/jmcomic/__init__.py @@ -2,7 +2,7 @@ # 被依赖方 <--- 使用方 # config <--- entity <--- toolkit <--- client <--- option <--- downloader -__version__ = '2.6.14' +__version__ = '2.6.15' from .api import * from .jm_plugin import * diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 2b99b3d4d..3c4885d74 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -1,5 +1,9 @@ +import logging + from common import time_stamp, field_cache, ProxyBuilder +jm_logger = logging.getLogger('jmcomic') + def shuffled(lines): from random import shuffle @@ -9,9 +13,27 @@ def shuffled(lines): return ls -def default_jm_logging(topic: str, msg: str): - from common import format_ts, current_thread - print('[{}] [{}]:【{}】{}'.format(format_ts(), current_thread().name, topic, msg)) +def setup_default_jm_logger(): + # 为了保持原有默认向下兼容,如果没有 handler,我们加一个控制台 handler + if not jm_logger.handlers: + import sys + handler = logging.StreamHandler(sys.stdout) + formatter = logging.Formatter('[%(asctime)s] [%(threadName)s]:【%(topic)s】%(message)s', datefmt='%Y-%m-%d %H:%M:%S') + handler.setFormatter(formatter) + jm_logger.addHandler(handler) + jm_logger.setLevel(logging.INFO) + + +def default_jm_logging(topic: str, msg, e: Exception = None): + # 支持 jm_log('topic', e) 的简写 + if isinstance(msg, BaseException): + e = msg + msg = str(msg) + extra = {'topic': topic} + if e is not None: + jm_logger.error(msg, extra=extra, exc_info=e) + else: + jm_logger.info(msg, extra=extra) # 禁漫常量 @@ -382,11 +404,10 @@ def get_fix_ts_token_tokenparam(cls): token, tokenparam = JmCryptoTool.token_and_tokenparam(ts) return ts, token, tokenparam - # noinspection PyUnusedLocal @classmethod - def jm_log(cls, topic: str, msg: str): + def jm_log(cls, topic: str, msg: str, e: Exception = None): if cls.FLAG_ENABLE_JM_LOG is True: - cls.EXECUTOR_LOG(topic, msg) + cls.EXECUTOR_LOG(topic, msg, e) @classmethod def disable_jm_log(cls): @@ -507,5 +528,7 @@ def register_exception_listener(cls, etype, listener): cls.REGISTRY_EXCEPTION_LISTENER[etype] = listener +setup_default_jm_logger() + jm_log = JmModuleConfig.jm_log disable_jm_log = JmModuleConfig.disable_jm_log diff --git a/src/jmcomic/jm_exception.py b/src/jmcomic/jm_exception.py index 8305277bc..987ec0fc5 100644 --- a/src/jmcomic/jm_exception.py +++ b/src/jmcomic/jm_exception.py @@ -6,6 +6,7 @@ class JmcomicException(Exception): description = 'jmcomic 模块异常' def __init__(self, msg: str, context: dict): + super().__init__(msg) self.msg = msg self.context = context diff --git a/src/jmcomic/jm_option.py b/src/jmcomic/jm_option.py index c7e3c8144..d1841494a 100644 --- a/src/jmcomic/jm_option.py +++ b/src/jmcomic/jm_option.py @@ -541,7 +541,7 @@ def call_all_plugin(self, group: str, safe=True, **extra): self.invoke_plugin(pclass, kwargs, extra, pinfo) except BaseException as e: if safe is True: - traceback_print_exec() + jm_log('plugin.exception', e) else: raise e diff --git a/src/jmcomic/jm_plugin.py b/src/jmcomic/jm_plugin.py index 8c2d5b8b3..e78188af6 100644 --- a/src/jmcomic/jm_plugin.py +++ b/src/jmcomic/jm_plugin.py @@ -552,15 +552,19 @@ def invoke(self, whitelist) -> None: if whitelist is not None: whitelist = set(whitelist) - old_jm_log = JmModuleConfig.EXECUTOR_LOG + import logging + from jmcomic import jm_logger - def new_jm_log(topic, msg): - if whitelist is not None and topic not in whitelist: - return - - old_jm_log(topic, msg) + class TopicFilter(logging.Filter): + def filter(self, record): + topic = getattr(record, 'topic', None) + if whitelist is not None and topic is not None and topic not in whitelist: + return False + return True - JmModuleConfig.EXECUTOR_LOG = new_jm_log + # 删除旧的同类 filter 避免重复 + jm_logger.filters = [f for f in jm_logger.filters if not isinstance(f, TopicFilter)] + jm_logger.addFilter(TopicFilter()) class AutoSetBrowserCookiesPlugin(JmOptionPlugin): @@ -1286,9 +1290,7 @@ def do_request(domain): try: return do_request(domain) except Exception as e: - from common import traceback_print_exec - traceback_print_exec() - jm_log('req.error', str(e)) + jm_log('req.error', e) self.update_failed_count(client, domain) return client.fallback(request, url, 0, 0, is_image, **kwargs) From 8d4090a948fb89d5cdf06cd4473ff9f381656bd1 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 15:29:50 +0800 Subject: [PATCH 02/14] =?UTF-8?q?docs:=20=E5=A2=9E=E5=8A=A0=20CONTRIBUTING?= =?UTF-8?q?.md=EF=BC=8C=E6=98=8E=E7=A1=AE=E4=BB=A3=E7=A0=81=E8=B4=A1?= =?UTF-8?q?=E7=8C=AE=E5=92=8C=E5=BC=80=E5=8F=91=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 124 +++++++++++++++++++++++++++++++++++++ README.md | 21 ++++--- assets/readme/README-en.md | 16 +++-- assets/readme/README-jp.md | 16 +++-- assets/readme/README-kr.md | 16 +++-- 5 files changed, 166 insertions(+), 27 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..377fc8d83 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,124 @@ +# 🤝 参与贡献 (Contributing) + +首先,非常感谢每一位愿意为 `jmcomic` 贡献代码和力量的机长!将 `jmcomic` 驶向更广阔的天空,离不开各位的添砖加瓦。 + +如果把每一次启动爬虫看作是一次狂热的航班起飞,那么这份文档就是塔台(仓库维护者)下发的**飞行手册与航权指南**。在改造战机、请求起飞之前,请务必花两分钟阅读这套协同规则。 + +## 💡 航前申报 (Before Writing Code) + +如果你的航线规划(代码改动)涉及核心组件或者需要编写超过几行代码,**强烈建议你先通过提交一个 Issue 向塔台申请**,详细讨论你想要拓展的功能或重构的想法。 + +在投入大量燃油(精力)之前,我们应该先在技术路线和实现方式上达成一致,避免你的心血被白白浪费或航线规划不被塔台接受。 + +## 💻 登机准备与试飞 (Build and Test) + +### 1. 组装战机 (Build) + +参与贡献的第一步,是将本项目 **[Fork](https://github.com/hect0x7/JMComic-Crawler-Python/fork)** 到你个人的机库(GitHub 账号)下,然后克隆到控制台,并独立切出你的任务分支: + +```bash +git clone https://github.com//JMComic-Crawler-Python.git +cd JMComic-Crawler-Python +git checkout dev +git checkout -b +``` + +强烈建议使用现代化的包管理器(如 [uv](https://github.com/astral-sh/uv))进行极速的沙盒隔离开发,避免污染你本地的系统空域: + +```bash +# 自动打通虚拟环境并注满燃油(安装源码及开发依赖) +uv venv +uv pip install -r requirements-dev.txt -e ./ +``` + +### 2. 空中改造 (Coding) + +在战机组装完毕并建立好安全的沙盒后,你就可以开始编写代码进行你的改装了。 + +在动工之前,请务必仔细阅读本文档末尾的《[🛠️ 引擎改装规范(Coding Guidelines)](#%EF%B8%8F-引擎改装规范-coding-guidelines)》 部分。那里记载了你必须要遵守的架构底线(如统一日志与异常拆解机制)。这能确保你的航线设计不偏离塔台的预设轨迹,避免在安检时因为违规操作被打回。 + +### 3. 试飞运行 (Test) + +向原仓库 `dev` 航道发起 PR 之前,你需要作为机长执行跑道级自检,**请务必保证你新编撰的代码能够顺利通过试飞用例**。 + +你可以任选以下两种自检方式之一: + +**选项 A:本地试飞 (终端测试)** +本项目使用 Python 标准库 `unittest` 作为本地质检验证,跑通所有测试: +```bash +cd ./tests/ +uv run python -m unittest +``` + +**选项 B:云端试飞 (GitHub Actions)** +如果你的本地环境不便配置,也可以直接将代码推送至你个人 Fork 仓库的 `dev` 分支。云端塔台会在后台自动触发 `test_api.yml` 动作。 +> 💡 请前往你个人仓库的 **Actions** 面板,确保最新的推流全部亮起绿灯。 + +## 📥 申请接入航线 (Pull Request) + +`jmcomic` 的代码管线有着极其明确的空域隔离,发起 PR 时请务必挂对你的目标分支: + +- 🟢 **`dev` 航道 (代码开发)**:所有的**功能特性 (feat)**、**功能重构 (refactor)** 或 **Bug 修复 (fix)** 的 PR,均需指向原仓库的 `dev` 航道。由塔台(维护者)合并试飞后集中推向主发版链路。 + +- 📘 **`docs` 航道 (文档维护)**:本航道直通项目专属的 **[在线文档 (Read the Docs)](https://jmcomic.readthedocs.io/zh-cn/latest/)**。所有不涉及功能性代码修改的**纯粹文档更新**,请直接提交至此分支。入线后它将即刻触发并全网同步部署,绕过复杂的流水安检。需要注意的是,`docs` 航道的进度通常会超前于主系统 (`master`),塔台会在新版发布或定期检修时统一将二者对齐同步。 + +- 🚫 **禁飞区 (禁止直飞 master)**:为防止外部航班意外触发 `release_auto.yml` 这个威力巨大的自动发版工作流,**本项目不接受任何直接指向 `master` 分支的 PR**。所有的新功能与代码改造必须经由 `dev` 航道降落并完成试飞,新版本号的最终敲定与发布由塔台统一操控。 + +PR 申请后,我会尽快 review 各位机长的代码并反馈通讯。再次感谢你的付出!🎉 + +--- + +## 🛠️ 引擎改装规范 (Coding Guidelines) + +> 📌 **塔台公告**:本《引擎改装规范》将伴随舰队的探索进度**持续迭代更新**。当前的强制适航指令主要聚焦于 **黑匣子 (日志记录)** 与 **空难溯源 (异常处理)** 两大核心电传模块。 + +### 📝 测试与操作手册 (Tests & Docs) + +在完成代码改造后,机长请务必补全以下配套设施,这是确保新战机安全入库的必要纲领: + +- **补充伴飞测试 (Tests)**:如果你打造了新型挂载(新功能)或排查掉了深层故障(Bug),你必须在 `tests/` 目录下为其编写对应的试飞用例。每一行核心代码都应当能通过稳定飞行测试。 +- **更新操作手册 (Docs)**:如果你实现了向其他机长开放的新仪表盘能力(功能入口),你还需要同步更新操作手册。文档应安放在 `assets/docs/` 下的对应位置。如果不知道该放哪,欢迎在 PR 中呼叫塔台。 + +--- + +### 💻 核心架构指令 (Architecture Rules) + +在为 `jmcomic` 编写或改造代码时,请尽量增加类型注解 (Type hints) 并遵守合理的命名。除此之外,为确保全机队的统一性,请尽量遵循以下架构规范: + +#### 1. 统一使用黑匣子网关 (统一日志) +所有的业务代码请统一使用 `from jmcomic import jm_log` 进行留痕。**避免**直接 `import logging` 或手动去拼接带有 `【】` 的日志头: +```python +from jmcomic import jm_log + +# ❌ 避免直接调用底层 logger +jm_logger.info("【api】请求成功") + +# ✅ 推荐做法,统一走网关,系统会自动套用格式化主题 +jm_log('api', '请求成功') +``` + +#### 2. 优雅记录坠机日志 (异常处理) +在飞行途中捕获到不可预料的 Exception 时,**无需**使用 `traceback.format_exc()` 费力拼装栈残骸。直接将异常对象作为入参传入 `jm_log` 即可,底层引擎会自动完整解析现场: +```python +try: + do_something() +except Exception as e: + # ❌ 避免手动拼装残骸,否则日志过滤系统会把它当成纯文本 + import traceback + jm_log('req.error', f'{e}\n{traceback.format_exc()}') + + # ✅ 推荐做法:直接上交异常对象本体,清爽且精准 + jm_log('req.error', e) +``` + +#### 3. 触发系统级警报 (统一抛错) +当发生预期的业务级阻断时,请尽量避免直接抛出内置的裸 Exception。通过内置的 `ExceptionTool` 抛出,能确保异常准确传达给用户外部装配的监听器 (`ExceptionListener`): +```python +from jmcomic import ExceptionTool + +# ❌ 避免直接 raise 底层异常,这会导致外部监听器失效 +raise Exception("解析 json 数据失败") + +# ✅ 推荐做法:通过工具类附带上下文信息抛出 +ExceptionTool.raises_resp(msg="解析 json 数据失败", resp=response) +``` diff --git a/README.md b/README.md index 2529466dd..518b78b47 100644 --- a/README.md +++ b/README.md @@ -23,17 +23,17 @@ - - > 本项目封装了一套可用于爬取JM的Python API. > > 你可以通过简单的几行Python代码,实现下载JM上的本子到本地,并且是处理好的图片。 > +> **🧭 快速指路** +> - [教程:使用 GitHub Actions 下载禁漫本子](./assets/docs/sources/tutorial/1_github_actions.md) +> - [教程:导出并下载你的禁漫收藏夹数据](./assets/docs/sources/tutorial/10_export_favorites.md) +> - [塔台广播:欢迎各位机长加入并贡献代码](./CONTRIBUTING.md) +> > **友情提示:珍爱JM,为了减轻JM的服务器压力,请不要一次性爬取太多本子,西门🙏🙏🙏**. - -[【指路】教程:使用GitHub Actions下载禁漫本子](./assets/docs/sources/tutorial/1_github_actions.md) - -[【指路】教程:导出并下载你的禁漫收藏夹数据](./assets/docs/sources/tutorial/10_export_favorites.md) +> ![introduction.jpg](./assets/docs/sources/images/introduction.jpg) @@ -59,7 +59,8 @@ ## 安装教程 -> ⚠如果你没有安装过Python,需要先安装Python再执行下面的步骤,且版本需要>=3.7([点我去python官网下载](https://www.python.org/downloads/)) +> ⚠如果你没有安装过 Python,需要先前往 [Python 官网下载](https://www.python.org/downloads/) 再执行以下步骤。 +>**推荐使用 Python 3.12及以上版本** * 通过pip官方源安装(推荐,并且更新也是这个命令) @@ -201,8 +202,10 @@ jmcomic 123 ## 使用小说明 -* Python >= 3.7,建议3.9以上,因为jmcomic的依赖库可能会不支持3.9以下的版本。 -* 个人项目,文档和示例会有不及时之处,可以Issue提问 +* 推荐使用 **Python 3.12+**,目前最低兼容版本为3.9。 + > 注意:Python 3.9 及更早版本皆已于 2025 年彻底结束官方生命周期 (EOL),使用3.9及以下随时有可能遇到第三方库不兼容的问题。 + +* 个人项目,文档和示例会有不及时之处,可以Issue提问。 ## 项目文件夹介绍 diff --git a/assets/readme/README-en.md b/assets/readme/README-en.md index 89cb523d4..ba3f9ab24 100644 --- a/assets/readme/README-en.md +++ b/assets/readme/README-en.md @@ -29,12 +29,13 @@ > > With a few simple lines of Python code, you can download albums from JM to your local machine, with properly processed images. > +> **🧭 Quick Guide** +> - [Tutorial: Downloading JM Albums using GitHub Actions](../docs/sources/tutorial/1_github_actions.md) +> - [Tutorial: Exporting and downloading your JM favorites data](../docs/sources/tutorial/10_export_favorites.md) +> - [Tower Broadcast: Welcome captains to join and contribute code](../../CONTRIBUTING.md) +> > **Friendly Prompt: Cherish JM. In order to reduce the pressure on JM servers, please do not download too many albums at once 🙏🙏🙏.** -[【Guide】Tutorial: Downloading JM Albums using GitHub Actions](../docs/sources/tutorial/1_github_actions.md) - -[【Guide】Tutorial: Exporting and downloading your JM favorites data](../docs/sources/tutorial/10_export_favorites.md) - ![introduction.jpg](../docs/sources/images/introduction.jpg) @@ -59,7 +60,8 @@ In addition to downloading, other JM interfaces are also implemented on demand. ## Installation Guide -> ⚠ If you have not installed Python, you must install Python before executing the following steps. Version >= 3.7 is required ([Download from Python Official Site](https://www.python.org/downloads/)). +> ⚠ If you have not installed Python, you must install Python before executing the following steps. [Download from Python Official Site](https://www.python.org/downloads/) +> **Version 3.12+ is recommended.** * Install via official pip source (recommended, the update command is identical) @@ -200,7 +202,9 @@ Please check the documentation homepage → [jmcomic.readthedocs.io (Chinese lan ## Prerequisites -* Python >= 3.7. Version 3.9+ is highly recommended because `jmcomic`'s dependencies may not perfectly support prior versions. +* Version **3.12+** is recommended, with a minimum compatible version of 3.9. + > Note: Python 3.9 and earlier versions reached their End Of Life (EOL) in 2025. You may encounter third-party library incompatibilities at any time if you use version 3.9 or below. + * Since this is a personal project, the documentation/examples may occasionally be out of sync. Please feel free to open an Issue for any clarifications. ## Directory Structure diff --git a/assets/readme/README-jp.md b/assets/readme/README-jp.md index 5aab7e21a..84ee3f542 100644 --- a/assets/readme/README-jp.md +++ b/assets/readme/README-jp.md @@ -29,12 +29,13 @@ > > 数行のPythonコードだけで、JM上のアルバムをローカルへダウンロードすることができます。ダウンロードされた画像は完全に処理済みです。 > +> **🧭 クイックガイド** +> - [チュートリアル: GitHub Actionsを使ってダウンロードする](../docs/sources/tutorial/1_github_actions.md) +> - [チュートリアル: お気に入りのデータをエクスポートしてダウンロードする](../docs/sources/tutorial/10_export_favorites.md) +> - [タワーブロードキャスト: 機長のみなさん、参加とコード提供を歓迎します](../../CONTRIBUTING.md) +> > **ご案内:JMのサーバー負荷を軽減するため、一度に大量のダウンロードは控えてください 🙏🙏🙏** -[【ガイド】チュートリアル:GitHub Actionsを使ってダウンロードする](../docs/sources/tutorial/1_github_actions.md) - -[【ガイド】チュートリアル:お気に入りのデータをエクスポートしてダウンロードする](../docs/sources/tutorial/10_export_favorites.md) - ![introduction.jpg](../docs/sources/images/introduction.jpg) @@ -59,7 +60,8 @@ ## インストール手順 -> ⚠ まだPythonをインストールしていない場合は、先にPythonのインストールをお願いします。要件: Python >= 3.7 ([公式のPythonページからダウンロード](https://www.python.org/downloads/))。 +> ⚠ まだPythonをインストールしていない場合は、先に [公式のPythonページからダウンロード](https://www.python.org/downloads/) してインストールをお願いします。 +> **Python 3.12以上の使用を推奨します** * 公式 pip ソースからインストール(推奨。アップデートもこのコマンドを使用します) @@ -199,7 +201,9 @@ jmcomic 123 ## ご利用上の注意点 -* Python >= 3.7 ですが、jmcomicの依存ライブラリが古いバージョンをサポートしない可能性があるため、3.9以上をお勧めします。 +* **Python 3.12以上**を推奨します。現在の最小互換バージョンは3.9です。 + > 注意: Python 3.9 およびそれ以前のバージョンは2025年に完全にサポート終了 (EOL) となっており、3.9以下のバージョンを使用すると、サードパーティ製ライブラリの非互換性の問題がいつでも発生する可能性があります。 + * 個人のプロジェクトであるため、ドキュメントやサンプルコードの更新が遅れることがあります。ご不明な点はIssueにてご質問ください。 ## ディレクトリ構造のご紹介 diff --git a/assets/readme/README-kr.md b/assets/readme/README-kr.md index ffea01101..5dd217942 100644 --- a/assets/readme/README-kr.md +++ b/assets/readme/README-kr.md @@ -29,12 +29,13 @@ > > 몇 줄의 간단한 Python 코드만으로 JM의 앨범을 로컬로 원활하게 다운로드할 수 있으며, 이미지 또한 모두 처리된 상태입니다. > +> **🧭 빠른 가이드** +> - [튜토리얼: GitHub Actions를 사용하여 다운로드하기](../docs/sources/tutorial/1_github_actions.md) +> - [튜토리얼: 즐겨찾기 데이터를 내보내고 다운로드하기](../docs/sources/tutorial/10_export_favorites.md) +> - [타워 브로드캐스트: 기장 여러분의 소스 코드 기여와 동참을 환영합니다](../../CONTRIBUTING.md) +> > **안내: JM 서버의 부하를 줄이기 위해 한 번에 너무 많은 앨범을 다운로드하지 말아주세요 🙏🙏🙏** -[【가이드】튜토리얼: GitHub Actions를 사용하여 다운로드하기](../docs/sources/tutorial/1_github_actions.md) - -[【가이드】튜토리얼: 즐겨찾기 데이터를 내보내고 다운로드하기](../docs/sources/tutorial/10_export_favorites.md) - ![introduction.jpg](../docs/sources/images/introduction.jpg) @@ -59,7 +60,8 @@ ## 설치 가이드 -> ⚠ Python이 시스템에 설치되어 있지 않다면, 다음 단계를 진행하기 전에 반드시 Python을 먼저 설치해주시기 바랍니다. 필요 버전 >= 3.7 ([Python 공식 사이트에서 다운로드하기](https://www.python.org/downloads/)). +> ⚠ Python이 시스템에 설치되어 있지 않다면, 다음 단계를 진행하기 전에 먼저 [Python 공식 사이트](https://www.python.org/downloads/) 에서 다운로드하여 설치해주시기 바랍니다. +> **Python 3.12 이상 버전을 권장합니다** * 공식 pip 저장소를 통한 설치 (추천. 업데이트 명령어도 동일합니다) @@ -199,7 +201,9 @@ jmcomic 123 ## 사용 팁 -* Python 3.7 이상을 요구하지만, 라이브러리와 jmcomic 패키지의 충돌을 막기 위해 3.9 이상의 쓰임을 추천합니다. +* **Python 3.12 이상**을 권장하며, 현재 최소 호환 버전은 3.9입니다. + > 참고: Python 3.9 및 이전 버전은 모두 2025년에 공식 지원 종료(EOL)되었으므로 3.9 이하 버전을 사용할 경우 언제든 서드파티 라이브러리 호환성 문제에 부딪힐 수 있습니다. + * 여유 시간에 만들어 지는 프로젝트이기에 정보나 활용 코드의 늦은 갱신이 다분합니다. 이슈(Issue)페이지로 연락주시기 바랍니다! ## 프로젝트 폴더 안내 From 54841de349fdf6ebad1c69393adf5da9ff554575 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:03:48 +0800 Subject: [PATCH 03/14] =?UTF-8?q?build:=20=E7=A7=BB=E9=99=A4=E5=B7=B2=20EO?= =?UTF-8?q?L=20=E7=9A=84=20Python=203.7/3.8=20classifiers=EF=BC=8C?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=E6=9C=80=E4=BD=8E=E7=89=88=E6=9C=AC=E8=A6=81?= =?UTF-8?q?=E6=B1=82=E4=B8=BA=203.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 +--- setup.py | 5 ++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bd564b630..f84783293 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,15 +6,13 @@ name = "jmcomic" authors = [{name = "hect0x7", email = "93357912+hect0x7@users.noreply.github.com"}] description = "Python API For JMComic (禁漫天堂)" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.9" license = {file = "LICENSE"} keywords=['python', 'jmcomic', '18comic', '禁漫天堂', 'NSFW'] classifiers=[ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/setup.py b/setup.py index bf95cb9a8..f7ab5ad1d 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ author_email='93357912+hect0x7@users.noreply.github.com', packages=find_packages("src"), package_dir={"": "src"}, - python_requires=">=3.7", + python_requires=">=3.9", install_requires=[ 'curl_cffi', 'commonX', @@ -37,8 +37,7 @@ classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", From a15ad2decc545cc80d14ada5c0653f910f1b7886 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:05:52 +0800 Subject: [PATCH 04/14] =?UTF-8?q?build:=20=E6=B7=BB=E5=8A=A0=20Python=203.?= =?UTF-8?q?14=20=E6=94=AF=E6=8C=81=EF=BC=8C=E6=B5=8B=E8=AF=95=E7=9F=A9?= =?UTF-8?q?=E9=98=B5=E6=9B=B4=E6=96=B0=E4=B8=BA=203.9/3.10/3.13/3.14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test_api.yml | 2 +- pyproject.toml | 1 + setup.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_api.yml b/.github/workflows/test_api.yml index a1089a308..48dfcacf6 100644 --- a/.github/workflows/test_api.yml +++ b/.github/workflows/test_api.yml @@ -16,7 +16,7 @@ jobs: test: # This code is based on https://github.com/gaogaotiantian/viztracer/blob/master/.github/workflows/python-package.yml strategy: matrix: - python-version: ['3.9', '3.10', '3.11', '3.13'] + python-version: ['3.9', '3.10', '3.13', '3.14'] os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} timeout-minutes: 5 diff --git a/pyproject.toml b/pyproject.toml index f84783293..966711047 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,6 +18,7 @@ classifiers=[ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Operating System :: Microsoft :: Windows", diff --git a/setup.py b/setup.py index f7ab5ad1d..5ffbff495 100644 --- a/setup.py +++ b/setup.py @@ -37,12 +37,12 @@ classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Operating System :: Microsoft :: Windows", From 10bfae91e752a192dc9deb7f009e29a8f63be23b Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:11:33 +0800 Subject: [PATCH 05/14] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20PR=20#516=20r?= =?UTF-8?q?eview=20=E9=97=AE=E9=A2=98=20(=E8=AF=AD=E6=B3=95/TopicFilter?= =?UTF-8?q?=E5=8E=BB=E9=87=8D/Formatter=20defaults)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md | 4 ++-- src/jmcomic/jm_config.py | 2 +- src/jmcomic/jm_plugin.py | 25 +++++++++++++++---------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 377fc8d83..f23909749 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,7 +52,7 @@ uv run python -m unittest **选项 B:云端试飞 (GitHub Actions)** 如果你的本地环境不便配置,也可以直接将代码推送至你个人 Fork 仓库的 `dev` 分支。云端塔台会在后台自动触发 `test_api.yml` 动作。 -> 💡 请前往你个人仓库的 **Actions** 面板,确保最新的推流全部亮起绿灯。 +> 💡 请前往你个人仓库的 **Actions** 面板,确保最新地推流全部亮起绿灯。 ## 📥 申请接入航线 (Pull Request) @@ -83,7 +83,7 @@ PR 申请后,我会尽快 review 各位机长的代码并反馈通讯。再次 ### 💻 核心架构指令 (Architecture Rules) -在为 `jmcomic` 编写或改造代码时,请尽量增加类型注解 (Type hints) 并遵守合理的命名。除此之外,为确保全机队的统一性,请尽量遵循以下架构规范: +在为 `jmcomic` 编写或改造代码时,请尽量增加类型注解 (Type hints) 并遵守合理地命名。除此之外,为确保全机队的统一性,请尽量遵循以下架构规范: #### 1. 统一使用黑匣子网关 (统一日志) 所有的业务代码请统一使用 `from jmcomic import jm_log` 进行留痕。**避免**直接 `import logging` 或手动去拼接带有 `【】` 的日志头: diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 3c4885d74..71c47fdcd 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -18,7 +18,7 @@ def setup_default_jm_logger(): if not jm_logger.handlers: import sys handler = logging.StreamHandler(sys.stdout) - formatter = logging.Formatter('[%(asctime)s] [%(threadName)s]:【%(topic)s】%(message)s', datefmt='%Y-%m-%d %H:%M:%S') + formatter = logging.Formatter('[%(asctime)s] [%(threadName)s]:【%(topic)s】%(message)s', datefmt='%Y-%m-%d %H:%M:%S', defaults={'topic': ''}) handler.setFormatter(formatter) jm_logger.addHandler(handler) jm_logger.setLevel(logging.INFO) diff --git a/src/jmcomic/jm_plugin.py b/src/jmcomic/jm_plugin.py index e78188af6..71cc8f83d 100644 --- a/src/jmcomic/jm_plugin.py +++ b/src/jmcomic/jm_plugin.py @@ -548,23 +548,28 @@ def invoke(self, class LogTopicFilterPlugin(JmOptionPlugin): plugin_key = 'log_topic_filter' + import logging + + class TopicFilter(logging.Filter): + def __init__(self, whitelist): + super().__init__() + self.whitelist = whitelist + + def filter(self, record): + topic = getattr(record, 'topic', None) + if self.whitelist is not None and topic is not None and topic not in self.whitelist: + return False + return True + def invoke(self, whitelist) -> None: if whitelist is not None: whitelist = set(whitelist) - import logging from jmcomic import jm_logger - class TopicFilter(logging.Filter): - def filter(self, record): - topic = getattr(record, 'topic', None) - if whitelist is not None and topic is not None and topic not in whitelist: - return False - return True - # 删除旧的同类 filter 避免重复 - jm_logger.filters = [f for f in jm_logger.filters if not isinstance(f, TopicFilter)] - jm_logger.addFilter(TopicFilter()) + jm_logger.filters = [f for f in jm_logger.filters if not isinstance(f, LogTopicFilterPlugin.TopicFilter)] + jm_logger.addFilter(LogTopicFilterPlugin.TopicFilter(whitelist)) class AutoSetBrowserCookiesPlugin(JmOptionPlugin): From 2bd7c4aadf41d218ce9a15f811b5138709e0b67d Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:16:28 +0800 Subject: [PATCH 06/14] =?UTF-8?q?revert:=20=E6=92=A4=E9=94=80=20jm=5Fconfi?= =?UTF-8?q?g.py=20=E4=B8=AD=E7=9A=84=20Formatter=20defaults=20=E5=8F=82?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E4=B8=8D=E5=85=BC=E5=AE=B9=203.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/jmcomic/jm_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 71c47fdcd..3c4885d74 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -18,7 +18,7 @@ def setup_default_jm_logger(): if not jm_logger.handlers: import sys handler = logging.StreamHandler(sys.stdout) - formatter = logging.Formatter('[%(asctime)s] [%(threadName)s]:【%(topic)s】%(message)s', datefmt='%Y-%m-%d %H:%M:%S', defaults={'topic': ''}) + formatter = logging.Formatter('[%(asctime)s] [%(threadName)s]:【%(topic)s】%(message)s', datefmt='%Y-%m-%d %H:%M:%S') handler.setFormatter(formatter) jm_logger.addHandler(handler) jm_logger.setLevel(logging.INFO) From c945542c328389f3b61655a8615b5907b6013895 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:21:50 +0800 Subject: [PATCH 07/14] =?UTF-8?q?fix:=20=E8=A1=A5=E5=85=85=203.9=20CI=20?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=E5=B9=B6=E7=A1=AE=E4=BF=9D=20jm=5Flog=20?= =?UTF-8?q?=E5=AF=B9=E6=97=A7=E7=89=88=20EXECUTOR=5FLOG=20=E7=9A=84?= =?UTF-8?q?=E5=90=91=E4=B8=8B=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test_api.yml | 2 +- src/jmcomic/jm_config.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_api.yml b/.github/workflows/test_api.yml index 48dfcacf6..8caaf5aaa 100644 --- a/.github/workflows/test_api.yml +++ b/.github/workflows/test_api.yml @@ -16,7 +16,7 @@ jobs: test: # This code is based on https://github.com/gaogaotiantian/viztracer/blob/master/.github/workflows/python-package.yml strategy: matrix: - python-version: ['3.9', '3.10', '3.13', '3.14'] + python-version: ['3.9', '3.10', '3.13', '3.14'] # 3.9 is kept as the minimum supported version test (EOL) os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} timeout-minutes: 5 diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 3c4885d74..3e247288e 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -407,7 +407,10 @@ def get_fix_ts_token_tokenparam(cls): @classmethod def jm_log(cls, topic: str, msg: str, e: Exception = None): if cls.FLAG_ENABLE_JM_LOG is True: - cls.EXECUTOR_LOG(topic, msg, e) + try: + cls.EXECUTOR_LOG(topic, msg, e) + except TypeError: + cls.EXECUTOR_LOG(topic, msg) @classmethod def disable_jm_log(cls): From 103a7b3fc4ae048f3748221e42c9cfb97b4fa406 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:25:17 +0800 Subject: [PATCH 08/14] =?UTF-8?q?v2.6.15:=20=E6=97=A5=E5=BF=97=E5=9F=BA?= =?UTF-8?q?=E4=BA=8Elogging=E9=87=8D=E6=9E=84;=20README=E6=9B=B4=E6=96=B0P?= =?UTF-8?q?ython=E7=89=88=E6=9C=AC=E8=A6=81=E6=B1=82=20(>=3D3.9);=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9Econtributing.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CONTRIBUTING.md => .github/CONTRIBUTING.md | 21 +++++++++++++++++++++ README.md | 2 +- assets/readme/README-en.md | 2 +- assets/readme/README-jp.md | 2 +- assets/readme/README-kr.md | 2 +- 5 files changed, 25 insertions(+), 4 deletions(-) rename CONTRIBUTING.md => .github/CONTRIBUTING.md (86%) diff --git a/CONTRIBUTING.md b/.github/CONTRIBUTING.md similarity index 86% rename from CONTRIBUTING.md rename to .github/CONTRIBUTING.md index f23909749..ffd1ed1cd 100644 --- a/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -68,6 +68,27 @@ PR 申请后,我会尽快 review 各位机长的代码并反馈通讯。再次 --- +## 🚀 发版巡航 (Release Process) + +项目使用自动化流水线进行发版,此流程仅由塔台(维护者)在合并至 `master` 分支时触发。 + +### 1. 触发条件 +当代码被推送(或 PR 合并)至 `master` 分支,且 **Commit Message 以 `v` 开头**时,GitHub Actions 会自动启动 `release_auto.yml` 工作流,执行以下操作: +1. 自动根据 Commit Message 创建 GitHub Release 标签。 +2. 自动构建项目并发布至 [PyPI](https://pypi.org/project/jmcomic/)。 + +### 2. Commit 格式指令 (仅针对维护者) +当塔台(维护者)准备好发布新版本并合入 `master` 时,需要根据 `.github/release.py` 的解析要求使用特定格式的 Commit Message: + +**格式:** `v<版本号>: <更新项1>; <更新项2>; ...` + +* **示例:** `v2.1.0: 修复搜索解析异常; 优化多线程下载效率; 新增插件系统` +* **黑匣子解析逻辑:** + * **Tag**:冒号 `:` 前的内容(如 `v2.1.0`)。 + * **Body**:冒号 `:` 后的内容,程序会将分号 `;` 分割的每一项转化为有序列表。 + +--- + ## 🛠️ 引擎改装规范 (Coding Guidelines) > 📌 **塔台公告**:本《引擎改装规范》将伴随舰队的探索进度**持续迭代更新**。当前的强制适航指令主要聚焦于 **黑匣子 (日志记录)** 与 **空难溯源 (异常处理)** 两大核心电传模块。 diff --git a/README.md b/README.md index 518b78b47..17629f2b5 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ > **🧭 快速指路** > - [教程:使用 GitHub Actions 下载禁漫本子](./assets/docs/sources/tutorial/1_github_actions.md) > - [教程:导出并下载你的禁漫收藏夹数据](./assets/docs/sources/tutorial/10_export_favorites.md) -> - [塔台广播:欢迎各位机长加入并贡献代码](./CONTRIBUTING.md) +> - [塔台广播:欢迎各位机长加入并贡献代码](./.github/CONTRIBUTING.md) > > **友情提示:珍爱JM,为了减轻JM的服务器压力,请不要一次性爬取太多本子,西门🙏🙏🙏**. > diff --git a/assets/readme/README-en.md b/assets/readme/README-en.md index ba3f9ab24..217f9b985 100644 --- a/assets/readme/README-en.md +++ b/assets/readme/README-en.md @@ -32,7 +32,7 @@ > **🧭 Quick Guide** > - [Tutorial: Downloading JM Albums using GitHub Actions](../docs/sources/tutorial/1_github_actions.md) > - [Tutorial: Exporting and downloading your JM favorites data](../docs/sources/tutorial/10_export_favorites.md) -> - [Tower Broadcast: Welcome captains to join and contribute code](../../CONTRIBUTING.md) +> - [Tower Broadcast: Welcome captains to join and contribute code](../../.github/CONTRIBUTING.md) > > **Friendly Prompt: Cherish JM. In order to reduce the pressure on JM servers, please do not download too many albums at once 🙏🙏🙏.** diff --git a/assets/readme/README-jp.md b/assets/readme/README-jp.md index 84ee3f542..bcd77c772 100644 --- a/assets/readme/README-jp.md +++ b/assets/readme/README-jp.md @@ -32,7 +32,7 @@ > **🧭 クイックガイド** > - [チュートリアル: GitHub Actionsを使ってダウンロードする](../docs/sources/tutorial/1_github_actions.md) > - [チュートリアル: お気に入りのデータをエクスポートしてダウンロードする](../docs/sources/tutorial/10_export_favorites.md) -> - [タワーブロードキャスト: 機長のみなさん、参加とコード提供を歓迎します](../../CONTRIBUTING.md) +> - [タワーブロードキャスト: 機長のみなさん、参加とコード提供を歓迎します](../../.github/CONTRIBUTING.md) > > **ご案内:JMのサーバー負荷を軽減するため、一度に大量のダウンロードは控えてください 🙏🙏🙏** diff --git a/assets/readme/README-kr.md b/assets/readme/README-kr.md index 5dd217942..e38130448 100644 --- a/assets/readme/README-kr.md +++ b/assets/readme/README-kr.md @@ -32,7 +32,7 @@ > **🧭 빠른 가이드** > - [튜토리얼: GitHub Actions를 사용하여 다운로드하기](../docs/sources/tutorial/1_github_actions.md) > - [튜토리얼: 즐겨찾기 데이터를 내보내고 다운로드하기](../docs/sources/tutorial/10_export_favorites.md) -> - [타워 브로드캐스트: 기장 여러분의 소스 코드 기여와 동참을 환영합니다](../../CONTRIBUTING.md) +> - [타워 브로드캐스트: 기장 여러분의 소스 코드 기여와 동참을 환영합니다](../../.github/CONTRIBUTING.md) > > **안내: JM 서버의 부하를 줄이기 위해 한 번에 너무 많은 앨범을 다운로드하지 말아주세요 🙏🙏🙏** From f4a64b87b8762d97c1cdc37c5b278a2dc7b33fe3 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:47:05 +0800 Subject: [PATCH 09/14] docs: satisfy PR review by clarifying jm_logger import in CONTRIBUTING.md --- .github/CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ffd1ed1cd..6dde7be49 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -109,9 +109,9 @@ PR 申请后,我会尽快 review 各位机长的代码并反馈通讯。再次 #### 1. 统一使用黑匣子网关 (统一日志) 所有的业务代码请统一使用 `from jmcomic import jm_log` 进行留痕。**避免**直接 `import logging` 或手动去拼接带有 `【】` 的日志头: ```python -from jmcomic import jm_log +from jmcomic import jm_log, jm_logger -# ❌ 避免直接调用底层 logger +# ❌ 避免直接调用底层 logger(jm_logger 是 jmcomic 内部原始的 logging.Logger 实例) jm_logger.info("【api】请求成功") # ✅ 推荐做法,统一走网关,系统会自动套用格式化主题 From ad692a1e3263a6a95328ff97d9df928c96a3c27a Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:52:22 +0800 Subject: [PATCH 10/14] refactor: optimize jm_log compatibility with arity detection and warnings --- src/jmcomic/jm_config.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 3e247288e..641a9a736 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -407,10 +407,23 @@ def get_fix_ts_token_tokenparam(cls): @classmethod def jm_log(cls, topic: str, msg: str, e: Exception = None): if cls.FLAG_ENABLE_JM_LOG is True: - try: - cls.EXECUTOR_LOG(topic, msg, e) - except TypeError: - cls.EXECUTOR_LOG(topic, msg) + executor = cls.EXECUTOR_LOG + if e is None: + executor(topic, msg) + else: + import inspect + try: + sig = inspect.signature(executor) + params_count = len(sig.parameters) + except (ValueError, TypeError): + params_count = 2 + + if params_count >= 3: + executor(topic, msg, e) + else: + import warnings + warnings.warn('jmcomic已升级到标准logging,建议将EXECUTOR_LOG重新定义为3个参数以接收异常对象 (topic, msg, e)') + executor(topic, msg) @classmethod def disable_jm_log(cls): From 9109b8fa1317fefea135ccd193f291ce09fc30de Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:58:38 +0800 Subject: [PATCH 11/14] docs: clarify logging customization methods in tutorial --- assets/docs/sources/tutorial/11_log_custom.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/assets/docs/sources/tutorial/11_log_custom.md b/assets/docs/sources/tutorial/11_log_custom.md index b3a226270..ed8828fd6 100644 --- a/assets/docs/sources/tutorial/11_log_custom.md +++ b/assets/docs/sources/tutorial/11_log_custom.md @@ -54,6 +54,13 @@ plugins: whitelist: [ api, ] ``` -## 4. 完全自定义 jmcomic 日志 +## 4. 深度自定义:两类不同的拦截手段 -你可以自定义jmcomic的模块日志打印函数,参考文档:[模块自定义](./4_module_custom.md#自定义log) +根据你的需求复杂度,你可以选择以下方式: + +- **方式 A:操作 jm_logger (推荐 / 标准)** + 适用于:改变日志输出位置(如文件、监控、后端服务)、调整显示格式、自定义过滤。 +- **方式 B:接管 EXECUTOR_LOG (高级 / 深度定制)** + 适用于:需要完全重塑日志的分发逻辑,或者将日志直接桥接到不符合标准 logging 协议的第三方系统。 + +详细参考文档:[模块自定义](./4_module_custom.md#自定义log) From 4e00a32362dce3e5e60b24f96d9ef4749f66fdcb Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:00:10 +0800 Subject: [PATCH 12/14] docs: fix awkward phrasing in custom log example --- assets/docs/sources/tutorial/4_module_custom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/docs/sources/tutorial/4_module_custom.md b/assets/docs/sources/tutorial/4_module_custom.md index bde8c4139..06274c6fd 100644 --- a/assets/docs/sources/tutorial/4_module_custom.md +++ b/assets/docs/sources/tutorial/4_module_custom.md @@ -161,7 +161,7 @@ def custom_jm_log(): """ pass - # 生效自定义的 proxy + # 生效自定义的 log 打印函数 JmModuleConfig.EXECUTOR_LOG = my_custom_log ``` From 41b07d3aae7030b3fee479f8124f95b53d72e8c0 Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:03:04 +0800 Subject: [PATCH 13/14] refactor: add stacklevel=2 to jm_log compatibility warning --- src/jmcomic/jm_config.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 641a9a736..59ab93ca5 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -422,7 +422,10 @@ def jm_log(cls, topic: str, msg: str, e: Exception = None): executor(topic, msg, e) else: import warnings - warnings.warn('jmcomic已升级到标准logging,建议将EXECUTOR_LOG重新定义为3个参数以接收异常对象 (topic, msg, e)') + warnings.warn( + 'jmcomic已升级到标准logging,建议将EXECUTOR_LOG重新定义为3个参数以接收异常对象 (topic, msg, e)', + stacklevel=2 + ) executor(topic, msg) @classmethod From 53b82e0e1dc799f4ea0be06aa1e1c622a4bf99cb Mon Sep 17 00:00:00 2001 From: hect0x7 <93357912+hect0x7@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:27:48 +0800 Subject: [PATCH 14/14] =?UTF-8?q?=E6=9B=B4=E6=96=B0docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/docs/sources/tutorial/11_log_custom.md | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/assets/docs/sources/tutorial/11_log_custom.md b/assets/docs/sources/tutorial/11_log_custom.md index ed8828fd6..66aefb5d6 100644 --- a/assets/docs/sources/tutorial/11_log_custom.md +++ b/assets/docs/sources/tutorial/11_log_custom.md @@ -6,16 +6,6 @@ ## 1. 日志完全开启/关闭 -使用代码: - -```python -from jmcomic import disable_jm_log -disable_jm_log() - -# 推荐使用 Python 原生的 logging 控制 -import logging -logging.getLogger("jmcomic").setLevel(logging.WARNING) # 只显示警告以上的日志 -``` 使用配置: @@ -23,6 +13,14 @@ logging.getLogger("jmcomic").setLevel(logging.WARNING) # 只显示警告以上 log: false ``` + +或者使用代码: + +```python +from jmcomic import disable_jm_log +disable_jm_log() +``` + ## 2. 日志过滤,只保留特定topic 使用插件配置 @@ -47,7 +45,7 @@ plugins: ```yaml plugins: after_init: - - plugin: client_proxy # 提高移动端的请求效率的插件 + - plugin: client_proxy log: false # 插件自身不打印日志 kwargs: proxy_client_key: photo_concurrent_fetcher_proxy @@ -59,8 +57,11 @@ plugins: 根据你的需求复杂度,你可以选择以下方式: - **方式 A:操作 jm_logger (推荐 / 标准)** + 适用于:改变日志输出位置(如文件、监控、后端服务)、调整显示格式、自定义过滤。 + - **方式 B:接管 EXECUTOR_LOG (高级 / 深度定制)** + 适用于:需要完全重塑日志的分发逻辑,或者将日志直接桥接到不符合标准 logging 协议的第三方系统。 详细参考文档:[模块自定义](./4_module_custom.md#自定义log)