manhuagui-cli 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -20
- package/README_EN.md +55 -20
- package/dist/lib/browser.d.ts +4 -0
- package/dist/lib/browser.d.ts.map +1 -0
- package/dist/lib/browser.js +22 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/chapter.d.ts +5 -1
- package/dist/lib/chapter.d.ts.map +1 -1
- package/dist/lib/chapter.js +97 -50
- package/dist/lib/chapter.js.map +1 -1
- package/dist/lib/cli.d.ts +20 -0
- package/dist/lib/cli.d.ts.map +1 -1
- package/dist/lib/cli.js +97 -63
- package/dist/lib/cli.js.map +1 -1
- package/dist/lib/comic.d.ts.map +1 -1
- package/dist/lib/comic.js +26 -17
- package/dist/lib/comic.js.map +1 -1
- package/dist/lib/config.d.ts +26 -19
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +92 -33
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/logger.d.ts +3 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +6 -2
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/progress.d.ts +1 -2
- package/dist/lib/progress.d.ts.map +1 -1
- package/dist/lib/progress.js +5 -12
- package/dist/lib/progress.js.map +1 -1
- package/dist/lib/prompts.d.ts +1 -0
- package/dist/lib/prompts.d.ts.map +1 -1
- package/dist/lib/prompts.js +9 -12
- package/dist/lib/prompts.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -75,26 +75,61 @@ node dist/index.js https://www.manhuagui.com/comic/12345/ --resume
|
|
|
75
75
|
|
|
76
76
|
### 选项
|
|
77
77
|
|
|
78
|
-
| 选项
|
|
79
|
-
|
|
|
80
|
-
| `--section <name>`
|
|
81
|
-
| `--chapter <name>`
|
|
82
|
-
| `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
| 选项 | 简写 | 说明 |
|
|
79
|
+
| --------------------- | ----- | --------------------------------------------- |
|
|
80
|
+
| `--section <name>` | `-s` | 指定要下载的章节组名称(默认:全部) |
|
|
81
|
+
| `--chapter <name>` | `-c` | 指定要下载的章节名称 |
|
|
82
|
+
| `--output <dir>` | `-o` | 下载输出目录 |
|
|
83
|
+
| `--concurrency <n>` | `-C` | 章节内图片并发下载数 |
|
|
84
|
+
| `--retry <n>` | | 图片下载重试次数 |
|
|
85
|
+
| `--log-level <level>` | | 日志级别:`debug` \| `info` \| `warn` \| `error` |
|
|
86
|
+
| `--resume` | `-r` | 断点续传模式 |
|
|
87
|
+
| `--dry-run` | `-d` | 预览模式(不实际下载) |
|
|
88
|
+
| `--help` | `-h` | 显示帮助信息 |
|
|
89
|
+
| `--version` | `-v` | 显示版本号 |
|
|
90
|
+
|
|
91
|
+
## 配置
|
|
92
|
+
|
|
93
|
+
所有配置项按以下优先级生效(高优先级覆盖低优先级):
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
CLI 参数 > 配置文件 > 环境变量 > 默认值
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 配置文件
|
|
100
|
+
|
|
101
|
+
支持两个位置的 JSON 配置文件,项目级覆盖全局级:
|
|
102
|
+
|
|
103
|
+
- **项目级**: `<当前目录>/.manhuaguirc.json`
|
|
104
|
+
- **全局**: `~/.config/manhuagui-cli/config.json`(Windows: `%USERPROFILE%\.config\manhuagui-cli\config.json`)
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"outputBase": "./downloads",
|
|
109
|
+
"imageConcurrency": 4,
|
|
110
|
+
"retryCount": 5,
|
|
111
|
+
"logLevel": "debug"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
全部可选,未指定的项使用默认值。
|
|
116
|
+
|
|
117
|
+
### 环境变量
|
|
118
|
+
|
|
119
|
+
复制 `.env.example` 为 `.env`,根据需要修改。也支持直接设置系统环境变量。
|
|
120
|
+
|
|
121
|
+
| 变量 | 默认值 | 说明 |
|
|
122
|
+
| --------------------- | ---------- | ---------------------------------------- |
|
|
123
|
+
| `OUTPUT_BASE` | `./output` | 下载输出目录 |
|
|
124
|
+
| `IMAGE_CONCURRENCY` | `2` | 章节内图片并发下载数 |
|
|
125
|
+
| `DOWNLOAD_DELAY` | `3000` | 图片批次之间延迟(毫秒,0 禁用) |
|
|
126
|
+
| `CHAPTER_DELAY_MIN` | `5000` | 章节间最小延迟(毫秒) |
|
|
127
|
+
| `CHAPTER_DELAY_MAX` | `15000` | 章节间最大延迟(毫秒) |
|
|
128
|
+
| `RETRY_COUNT` | `3` | 图片下载重试次数 |
|
|
129
|
+
| `RETRY_BACKOFF_BASE` | `1000` | 重试退避基准毫秒(第 N 次重试等待 N×base) |
|
|
130
|
+
| `IMAGE_LOAD_DELAY` | `200` | 翻页后等待图片加载时间(毫秒) |
|
|
131
|
+
| `LOG_LEVEL` | `info` | 日志级别:`debug` \| `info` \| `warn` \| `error` |
|
|
132
|
+
| `USER_AGENTS` | — | 自定义 User-Agent 列表(每行一个) |
|
|
98
133
|
|
|
99
134
|
## 输出目录结构
|
|
100
135
|
|
package/README_EN.md
CHANGED
|
@@ -75,26 +75,61 @@ node dist/index.js https://www.manhuagui.com/comic/12345/ --resume
|
|
|
75
75
|
|
|
76
76
|
### Options
|
|
77
77
|
|
|
78
|
-
| Option
|
|
79
|
-
|
|
|
80
|
-
| `--section <name>`
|
|
81
|
-
| `--chapter <name>`
|
|
82
|
-
| `--
|
|
83
|
-
| `--
|
|
84
|
-
| `--
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
| Option | Alias | Description |
|
|
79
|
+
| -------------------- | ----- | -------------------------------------------------------------- |
|
|
80
|
+
| `--section <name>` | `-s` | Download only the named section (default: all) |
|
|
81
|
+
| `--chapter <name>` | `-c` | Download only the named chapter |
|
|
82
|
+
| `--output <dir>` | `-o` | Download output directory |
|
|
83
|
+
| `--concurrency <n>` | `-C` | Concurrent image downloads per chapter |
|
|
84
|
+
| `--retry <n>` | | Retry count per image download |
|
|
85
|
+
| `--log-level <level>`| | Log level: `debug` \| `info` \| `warn` \| `error` |
|
|
86
|
+
| `--resume` | `-r` | Resume from previous interrupted download |
|
|
87
|
+
| `--dry-run` | `-d` | Preview mode (list chapters without downloading) |
|
|
88
|
+
| `--help` | `-h` | Show help |
|
|
89
|
+
| `--version` | `-v` | Show version |
|
|
90
|
+
|
|
91
|
+
## Configuration
|
|
92
|
+
|
|
93
|
+
All settings follow this priority order (higher overrides lower):
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
CLI args > config files > environment variables > defaults
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Config Files
|
|
100
|
+
|
|
101
|
+
Two JSON config file locations are supported, project-level overrides global:
|
|
102
|
+
|
|
103
|
+
- **Project-level**: `<cwd>/.manhuaguirc.json`
|
|
104
|
+
- **Global**: `~/.config/manhuagui-cli/config.json` (Windows: `%USERPROFILE%\.config\manhuagui-cli\config.json`)
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{
|
|
108
|
+
"outputBase": "./downloads",
|
|
109
|
+
"imageConcurrency": 4,
|
|
110
|
+
"retryCount": 5,
|
|
111
|
+
"logLevel": "debug"
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All fields are optional; defaults are used for any omitted field.
|
|
116
|
+
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
Copy `.env.example` to `.env` and modify as needed. System environment variables are also supported.
|
|
120
|
+
|
|
121
|
+
| Variable | Default | Description |
|
|
122
|
+
| --------------------- | ---------- | --------------------------------------------------- |
|
|
123
|
+
| `OUTPUT_BASE` | `./output` | Download output directory |
|
|
124
|
+
| `IMAGE_CONCURRENCY` | `2` | Concurrent image downloads per chapter |
|
|
125
|
+
| `DOWNLOAD_DELAY` | `3000` | Delay between image batches (ms, 0 to disable) |
|
|
126
|
+
| `CHAPTER_DELAY_MIN` | `5000` | Min delay between chapters (ms) |
|
|
127
|
+
| `CHAPTER_DELAY_MAX` | `15000` | Max delay between chapters (ms) |
|
|
128
|
+
| `RETRY_COUNT` | `3` | Retry count per image download |
|
|
129
|
+
| `RETRY_BACKOFF_BASE` | `1000` | Retry backoff base (ms), wait `N × base` on Nth retry |
|
|
130
|
+
| `IMAGE_LOAD_DELAY` | `200` | Wait after page turn for image to load (ms) |
|
|
131
|
+
| `LOG_LEVEL` | `info` | Log level: `debug` \| `info` \| `warn` \| `error` |
|
|
132
|
+
| `USER_AGENTS` | — | Custom User-Agent pool, one per line |
|
|
98
133
|
|
|
99
134
|
## Output Structure
|
|
100
135
|
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Browser, BrowserContext, Page } from "playwright";
|
|
2
|
+
export declare function createBrowserContext(browser: Browser): Promise<BrowserContext>;
|
|
3
|
+
export declare function handleAdultCheck(page: Page, waitFor?: string): Promise<void>;
|
|
4
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIhE,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAQpF;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASlF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { config, pickUserAgent } from "./config.js";
|
|
2
|
+
import { randInt } from "./utils.js";
|
|
3
|
+
export async function createBrowserContext(browser) {
|
|
4
|
+
return browser.newContext({
|
|
5
|
+
userAgent: pickUserAgent(),
|
|
6
|
+
viewport: {
|
|
7
|
+
width: randInt(config.viewportMinWidth, config.viewportMaxWidth),
|
|
8
|
+
height: randInt(config.viewportMinHeight, config.viewportMaxHeight),
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export async function handleAdultCheck(page, waitFor) {
|
|
13
|
+
const checkAdult = await page.$("#checkAdult");
|
|
14
|
+
if (checkAdult) {
|
|
15
|
+
await checkAdult.click();
|
|
16
|
+
if (waitFor) {
|
|
17
|
+
await page.waitForSelector(waitFor, { timeout: config.adultSelectorTimeout });
|
|
18
|
+
await page.waitForTimeout(config.adultClickSettleDelay);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/lib/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAgB;IACzD,OAAO,OAAO,CAAC,UAAU,CAAC;QACxB,SAAS,EAAE,aAAa,EAAE;QAC1B,QAAQ,EAAE;YACR,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,CAAC;YAChE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,CAAC;SACpE;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAU,EAAE,OAAgB;IACjE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAC/C,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC;YAC9E,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/lib/chapter.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type { Browser } from "playwright";
|
|
1
|
+
import type { Browser, Page as PlaywrightPage, Response } from "playwright";
|
|
2
2
|
export declare function computePadLength(count: number): number;
|
|
3
3
|
export declare function extractExtension(url: string): string;
|
|
4
4
|
export declare function buildFilePath(outputDir: string, index: number, padLen: number, ext: string): string;
|
|
5
|
+
export declare function getPageCount(page: PlaywrightPage): Promise<number>;
|
|
6
|
+
export declare function getSubPageUrls(page: PlaywrightPage): Promise<string[]>;
|
|
7
|
+
export declare function collectImageUrls(page: PlaywrightPage, pageCount: number): Promise<string[]>;
|
|
8
|
+
export declare function validateImageResponse(response: Response | null): void;
|
|
5
9
|
export declare function extractChapterImages(chapterUrl: string, browser: Browser, outputDir: string): Promise<string[]>;
|
|
6
10
|
//# sourceMappingURL=chapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chapter.d.ts","sourceRoot":"","sources":["../../src/lib/chapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"chapter.d.ts","sourceRoot":"","sources":["../../src/lib/chapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAkB,IAAI,IAAI,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAO5F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,wBAAgB,aAAa,CAC3B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,GACV,MAAM,CAGR;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAaxE;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAa5E;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA8BjG;AAYD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,CAQrE;AAyGD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB"}
|
package/dist/lib/chapter.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { createBrowserContext, handleAdultCheck } from "./browser.js";
|
|
4
|
+
import { config } from "./config.js";
|
|
4
5
|
import { rotateHost } from "./download.js";
|
|
5
6
|
import { logger } from "./logger.js";
|
|
6
|
-
import { ensureDir,
|
|
7
|
+
import { ensureDir, sleep } from "./utils.js";
|
|
7
8
|
export function computePadLength(count) {
|
|
8
|
-
return Math.max(
|
|
9
|
+
return Math.max(config.padMinLength, String(count).length);
|
|
9
10
|
}
|
|
10
11
|
export function extractExtension(url) {
|
|
11
12
|
const match = url.match(/\.(\w{3,4})(?:\?|$)/);
|
|
@@ -15,7 +16,7 @@ export function buildFilePath(outputDir, index, padLen, ext) {
|
|
|
15
16
|
const padNum = String(index + 1).padStart(padLen, "0");
|
|
16
17
|
return join(outputDir, `${padNum}.${ext}`);
|
|
17
18
|
}
|
|
18
|
-
async function getPageCount(page) {
|
|
19
|
+
export async function getPageCount(page) {
|
|
19
20
|
return page.evaluate(() => {
|
|
20
21
|
const pageSpan = document.querySelector("#page");
|
|
21
22
|
if (pageSpan?.parentElement) {
|
|
@@ -29,8 +30,25 @@ async function getPageCount(page) {
|
|
|
29
30
|
return 0;
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
|
-
async function
|
|
33
|
+
export async function getSubPageUrls(page) {
|
|
34
|
+
try {
|
|
35
|
+
await page.waitForSelector("#pagination a", { timeout: config.tabLoadTimeout });
|
|
36
|
+
return await page.evaluate(() => {
|
|
37
|
+
const links = document.querySelectorAll("#pagination a");
|
|
38
|
+
if (links.length <= 1)
|
|
39
|
+
return [];
|
|
40
|
+
return Array.from(links)
|
|
41
|
+
.map((a) => a.href)
|
|
42
|
+
.filter((href) => href.startsWith("http"));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export async function collectImageUrls(page, pageCount) {
|
|
33
50
|
const urls = [];
|
|
51
|
+
const pagePath = page.url().split("#")[0];
|
|
34
52
|
let currentUrl = await page.$eval("#mangaFile", (img) => img.src);
|
|
35
53
|
urls.push(currentUrl);
|
|
36
54
|
for (let i = 1; i < pageCount; i++) {
|
|
@@ -42,59 +60,75 @@ async function collectImageUrls(page, pageCount) {
|
|
|
42
60
|
await page.waitForFunction((prev) => {
|
|
43
61
|
const img = document.querySelector("#mangaFile");
|
|
44
62
|
return img !== null && img.src !== "" && img.src !== prev;
|
|
45
|
-
}, prevUrl, { timeout:
|
|
46
|
-
await page.waitForTimeout(
|
|
63
|
+
}, prevUrl, { timeout: config.nextPageTimeout });
|
|
64
|
+
await page.waitForTimeout(config.imageLoadDelay);
|
|
65
|
+
if (page.url().split("#")[0] !== pagePath)
|
|
66
|
+
break;
|
|
47
67
|
currentUrl = await page.$eval("#mangaFile", (img) => img.src);
|
|
48
68
|
urls.push(currentUrl);
|
|
49
69
|
}
|
|
50
70
|
return urls;
|
|
51
71
|
}
|
|
72
|
+
async function navigateToChapterPage(page, url) {
|
|
73
|
+
await page.goto(url, {
|
|
74
|
+
waitUntil: "domcontentloaded",
|
|
75
|
+
timeout: config.pageLoadTimeout,
|
|
76
|
+
});
|
|
77
|
+
await handleAdultCheck(page);
|
|
78
|
+
await page.waitForSelector("#mangaFile", { timeout: config.chapterSelectorTimeout });
|
|
79
|
+
}
|
|
80
|
+
export function validateImageResponse(response) {
|
|
81
|
+
if (response?.status() !== 200) {
|
|
82
|
+
throw new Error(`HTTP ${response?.status() ?? "no response"}`);
|
|
83
|
+
}
|
|
84
|
+
const contentType = response?.headers()?.["content-type"] ?? "";
|
|
85
|
+
if (contentType && !contentType.startsWith("image/")) {
|
|
86
|
+
throw new Error(`Unexpected content type: ${contentType}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function fetchImageAsBase64(page) {
|
|
90
|
+
return page.evaluate(async () => {
|
|
91
|
+
const res = await fetch(window.location.href);
|
|
92
|
+
if (!res.ok)
|
|
93
|
+
throw new Error(`Fetch failed: ${res.status}`);
|
|
94
|
+
const buf = await res.arrayBuffer();
|
|
95
|
+
const bytes = new Uint8Array(buf);
|
|
96
|
+
let binary = "";
|
|
97
|
+
const step = 0x8000;
|
|
98
|
+
for (let j = 0; j < bytes.length; j += step) {
|
|
99
|
+
binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(j, j + step)));
|
|
100
|
+
}
|
|
101
|
+
return btoa(binary);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
52
104
|
async function downloadImage(dlPage, chapterUrl, url, outputDir, imageIndex, padLen) {
|
|
53
105
|
const ext = extractExtension(url);
|
|
54
106
|
const filePath = buildFilePath(outputDir, imageIndex, padLen, ext);
|
|
55
107
|
let downloadUrl = url;
|
|
56
|
-
for (let attempt = 0; attempt <
|
|
108
|
+
for (let attempt = 0; attempt < config.retryCount; attempt++) {
|
|
57
109
|
try {
|
|
58
110
|
const response = await dlPage.goto(downloadUrl, {
|
|
59
111
|
referer: chapterUrl,
|
|
60
112
|
waitUntil: "load",
|
|
61
|
-
timeout:
|
|
62
|
-
});
|
|
63
|
-
if (response?.status() !== 200) {
|
|
64
|
-
throw new Error(`HTTP ${response?.status() ?? "no response"}`);
|
|
65
|
-
}
|
|
66
|
-
const contentType = response?.headers()?.["content-type"] ?? "";
|
|
67
|
-
if (contentType && !contentType.startsWith("image/")) {
|
|
68
|
-
throw new Error(`Unexpected content type: ${contentType}`);
|
|
69
|
-
}
|
|
70
|
-
const base64 = await dlPage.evaluate(async () => {
|
|
71
|
-
const res = await fetch(window.location.href);
|
|
72
|
-
if (!res.ok)
|
|
73
|
-
throw new Error(`Fetch failed: ${res.status}`);
|
|
74
|
-
const buf = await res.arrayBuffer();
|
|
75
|
-
const bytes = new Uint8Array(buf);
|
|
76
|
-
let binary = "";
|
|
77
|
-
const step = 0x8000;
|
|
78
|
-
for (let j = 0; j < bytes.length; j += step) {
|
|
79
|
-
binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(j, j + step)));
|
|
80
|
-
}
|
|
81
|
-
return btoa(binary);
|
|
113
|
+
timeout: config.pageLoadTimeout,
|
|
82
114
|
});
|
|
115
|
+
validateImageResponse(response);
|
|
116
|
+
const base64 = await fetchImageAsBase64(dlPage);
|
|
83
117
|
writeFileSync(filePath, Buffer.from(base64, "base64"));
|
|
84
118
|
return true;
|
|
85
119
|
}
|
|
86
120
|
catch {
|
|
87
|
-
if (attempt <
|
|
121
|
+
if (attempt < config.retryCount - 1) {
|
|
88
122
|
downloadUrl = rotateHost(downloadUrl);
|
|
89
|
-
await sleep(
|
|
123
|
+
await sleep(config.retryBackoffBase * (attempt + 1));
|
|
90
124
|
}
|
|
91
125
|
}
|
|
92
126
|
}
|
|
93
|
-
logger.warn(`Failed to download after ${
|
|
127
|
+
logger.warn(`Failed to download after ${config.retryCount} retries: ${url}`);
|
|
94
128
|
return false;
|
|
95
129
|
}
|
|
96
130
|
async function downloadImages(context, chapterUrl, outputDir, urls, padLen) {
|
|
97
|
-
const concurrency = Math.min(
|
|
131
|
+
const concurrency = Math.min(config.imageConcurrency, urls.length);
|
|
98
132
|
const downloadPages = await Promise.all(Array.from({ length: concurrency }, () => context.newPage()));
|
|
99
133
|
try {
|
|
100
134
|
for (let i = 0; i < urls.length; i += concurrency) {
|
|
@@ -102,8 +136,8 @@ async function downloadImages(context, chapterUrl, outputDir, urls, padLen) {
|
|
|
102
136
|
const results = await Promise.all(batch.map((url, idx) => downloadImage(downloadPages[idx], chapterUrl, url, outputDir, i + idx, padLen)));
|
|
103
137
|
if (results.some((r) => !r))
|
|
104
138
|
return;
|
|
105
|
-
if (
|
|
106
|
-
await sleep(Math.round(
|
|
139
|
+
if (config.downloadDelay > 0) {
|
|
140
|
+
await sleep(Math.round(config.downloadDelay * (0.5 + Math.random())));
|
|
107
141
|
}
|
|
108
142
|
}
|
|
109
143
|
}
|
|
@@ -111,26 +145,39 @@ async function downloadImages(context, chapterUrl, outputDir, urls, padLen) {
|
|
|
111
145
|
await Promise.all(downloadPages.map((p) => p.close()));
|
|
112
146
|
}
|
|
113
147
|
}
|
|
148
|
+
async function collectImageUrlsFromSubPages(page, subPageUrls) {
|
|
149
|
+
const allUrls = [];
|
|
150
|
+
for (let i = 0; i < subPageUrls.length; i++) {
|
|
151
|
+
if (i > 0) {
|
|
152
|
+
await navigateToChapterPage(page, subPageUrls[i]);
|
|
153
|
+
}
|
|
154
|
+
const tabPageCount = await getPageCount(page);
|
|
155
|
+
if (tabPageCount <= 0)
|
|
156
|
+
continue;
|
|
157
|
+
const tabUrls = await collectImageUrls(page, tabPageCount);
|
|
158
|
+
allUrls.push(...tabUrls);
|
|
159
|
+
}
|
|
160
|
+
return allUrls;
|
|
161
|
+
}
|
|
114
162
|
export async function extractChapterImages(chapterUrl, browser, outputDir) {
|
|
115
163
|
ensureDir(outputDir);
|
|
116
|
-
const context = await browser
|
|
117
|
-
userAgent: pickUserAgent(),
|
|
118
|
-
viewport: {
|
|
119
|
-
width: randInt(VIEWPORT_MIN_WIDTH, VIEWPORT_MAX_WIDTH),
|
|
120
|
-
height: randInt(VIEWPORT_MIN_HEIGHT, VIEWPORT_MAX_HEIGHT),
|
|
121
|
-
},
|
|
122
|
-
});
|
|
164
|
+
const context = await createBrowserContext(browser);
|
|
123
165
|
const page = await context.newPage();
|
|
124
166
|
try {
|
|
125
|
-
await page
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
167
|
+
await navigateToChapterPage(page, chapterUrl);
|
|
168
|
+
const subPageUrls = await getSubPageUrls(page);
|
|
169
|
+
let urls;
|
|
170
|
+
if (subPageUrls.length > 0) {
|
|
171
|
+
urls = await collectImageUrlsFromSubPages(page, subPageUrls);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
const pageCount = await getPageCount(page);
|
|
175
|
+
if (pageCount <= 0)
|
|
176
|
+
return [];
|
|
177
|
+
urls = await collectImageUrls(page, pageCount);
|
|
178
|
+
}
|
|
179
|
+
if (urls.length === 0)
|
|
132
180
|
return [];
|
|
133
|
-
const urls = await collectImageUrls(page, pageCount);
|
|
134
181
|
const padLen = computePadLength(urls.length);
|
|
135
182
|
await downloadImages(context, chapterUrl, outputDir, urls, padLen);
|
|
136
183
|
return urls;
|
package/dist/lib/chapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chapter.js","sourceRoot":"","sources":["../../src/lib/chapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,
|
|
1
|
+
{"version":3,"file":"chapter.js","sourceRoot":"","sources":["../../src/lib/chapter.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/cli.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Section } from "./types.js";
|
|
2
|
+
export declare function applyFilters(sections: Section[], sectionFilter?: string, chapterFilter?: string): Section[];
|
|
1
3
|
export declare const command: import("citty").CommandDef<{
|
|
2
4
|
readonly url: {
|
|
3
5
|
readonly type: "positional";
|
|
@@ -26,5 +28,23 @@ export declare const command: import("citty").CommandDef<{
|
|
|
26
28
|
readonly alias: "d";
|
|
27
29
|
readonly default: false;
|
|
28
30
|
};
|
|
31
|
+
readonly output: {
|
|
32
|
+
readonly type: "string";
|
|
33
|
+
readonly description: "下载输出目录 / Output directory for downloads";
|
|
34
|
+
readonly alias: "o";
|
|
35
|
+
};
|
|
36
|
+
readonly concurrency: {
|
|
37
|
+
readonly type: "string";
|
|
38
|
+
readonly description: "章节内图片并发下载数 / Concurrent image downloads per chapter";
|
|
39
|
+
readonly alias: "C";
|
|
40
|
+
};
|
|
41
|
+
readonly retry: {
|
|
42
|
+
readonly type: "string";
|
|
43
|
+
readonly description: "图片下载重试次数 / Retry count per image";
|
|
44
|
+
};
|
|
45
|
+
readonly "log-level": {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
readonly description: "日志级别: debug | info | warn | error / Log level";
|
|
48
|
+
};
|
|
29
49
|
}>;
|
|
30
50
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/lib/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/lib/cli.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAsB,OAAO,EAAE,MAAM,YAAY,CAAC;AAmB9D,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,EAAE,CAgBX;AAsPD,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6ElB,CAAC"}
|