Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test_api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Comment thread
hect0x7 marked this conversation as resolved.
Outdated
os: [ ubuntu-latest ]
runs-on: ${{ matrix.os }}
timeout-minutes: 5
Expand Down
124 changes: 124 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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/<your_user_name>/JMComic-Crawler-Python.git
cd JMComic-Crawler-Python
git checkout dev
git checkout -b <your_feature_branch>
```

强烈建议使用现代化的包管理器(如 [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)
```
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@
</div>




> 本项目封装了一套可用于爬取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)
Expand All @@ -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官方源安装(推荐,并且更新也是这个命令)

Expand Down Expand Up @@ -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提问。

## 项目文件夹介绍

Expand Down
6 changes: 5 additions & 1 deletion assets/docs/sources/tutorial/11_log_custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

使用代码:

```
```python
from jmcomic import disable_jm_log
disable_jm_log()

# 推荐使用 Python 原生的 logging 控制
import logging
logging.getLogger("jmcomic").setLevel(logging.WARNING) # 只显示警告以上的日志
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Split the two alternative approaches into separate, clearly labelled code blocks.

disable_jm_log() and logging.getLogger(...).setLevel(...) are mutually exclusive alternatives, but they are presented as a single sequential snippet. A reader who copies the block calls disable_jm_log() first (which disables all output) and then calls setLevel(logging.WARNING) — the outcome depends on how disable_jm_log is implemented and is at best confusing, at worst a silent no-op for the second call. The inline comment "推荐使用 Python 原生的 logging 控制" already signals that the second snippet is preferred, so presenting both in one block contradicts that recommendation.

📝 Proposed fix: separate into two distinct blocks
-```python
-from jmcomic import disable_jm_log 
-disable_jm_log()
-
-# 推荐使用 Python 原生的 logging 控制
-import logging
-logging.getLogger("jmcomic").setLevel(logging.WARNING) # 只显示警告以上的日志
-```
+**方式 A(推荐):使用 Python 原生 logging 控制**
+
+```python
+import logging
+logging.getLogger("jmcomic").setLevel(logging.WARNING)  # 只显示警告以上的日志
+```
+
+**方式 B:使用 `disable_jm_log()` 完全关闭日志**
+
+```python
+from jmcomic import disable_jm_log
+disable_jm_log()
+```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@assets/docs/sources/tutorial/11_log_custom.md` around lines 11 - 18, Split
the combined example into two separate, clearly labeled code blocks so readers
understand they are alternatives: create one block titled "方式 A(推荐):使用 Python 原生
logging 控制" showing use of
logging.getLogger("jmcomic").setLevel(logging.WARNING), and a second block
titled "方式 B:使用 disable_jm_log() 完全关闭日志" showing from jmcomic import
disable_jm_log and disable_jm_log(). Ensure the text explains they are mutually
exclusive alternatives and remove the single sequential snippet that mixes both.


使用配置:
Expand Down
28 changes: 18 additions & 10 deletions assets/docs/sources/tutorial/4_module_custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```


Expand Down
16 changes: 10 additions & 6 deletions assets/readme/README-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand Down
16 changes: 10 additions & 6 deletions assets/readme/README-jp.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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 ソースからインストール(推奨。アップデートもこのコマンドを使用します)

Expand Down Expand Up @@ -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にてご質問ください。

## ディレクトリ構造のご紹介
Expand Down
16 changes: 10 additions & 6 deletions assets/readme/README-kr.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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 저장소를 통한 설치 (추천. 업데이트 명령어도 동일합니다)

Expand Down Expand Up @@ -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)페이지로 연락주시기 바랍니다!

## 프로젝트 폴더 안내
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ 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",
"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",
Expand Down
Loading