@cloud411716/fancy-webnovel 0.2.27 → 0.2.28
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/package.json
CHANGED
|
@@ -73,8 +73,8 @@ export async function apply(ctx) {
|
|
|
73
73
|
: (row[2] === '长篇' ? 'long' : 'short');
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
//
|
|
77
|
-
if (platform === 'zhihu'
|
|
76
|
+
// 知乎二次选择篇幅(保持原逻辑)
|
|
77
|
+
if (platform === 'zhihu') {
|
|
78
78
|
if (!length || !['long', 'short'].includes(length)) {
|
|
79
79
|
const lenResult = await ctx.userQuestions.ask({
|
|
80
80
|
questions: [scan.askLength(platform)],
|
|
@@ -90,9 +90,30 @@ export async function apply(ctx) {
|
|
|
90
90
|
length = 'long';
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// 七猫二次选择(男/女频 × 大热/新书榜)
|
|
94
|
+
if (platform === 'qimao') {
|
|
95
|
+
const lenResult = await ctx.userQuestions.ask({
|
|
96
|
+
questions: [scan.askLength(platform)],
|
|
97
|
+
});
|
|
98
|
+
const lenAnswer = lenResult.answers[0]?.selected?.[0] ?? lenResult.answers[0]?.custom;
|
|
99
|
+
if (!lenAnswer || lenAnswer === '取消') {
|
|
100
|
+
notify(session, scan.notify({ type: 'cancelled' }));
|
|
101
|
+
return { kind: 'success', text: '' };
|
|
102
|
+
}
|
|
103
|
+
// 把选项标签映射成 channel + type,存入 ctx.options 供 runScanWithChromiumFix 传递
|
|
104
|
+
const qimaoMap = {
|
|
105
|
+
'采集全部(男/女 × 大热/新书,4个榜单)': { channel: 'all', type: 'all' },
|
|
106
|
+
'男生大热榜': { channel: 'male', type: 'hot' },
|
|
107
|
+
'男生新书榜': { channel: 'male', type: 'new' },
|
|
108
|
+
'女生大热榜': { channel: 'female', type: 'hot' },
|
|
109
|
+
'女生新书榜': { channel: 'female', type: 'new' },
|
|
110
|
+
};
|
|
111
|
+
ctx._qimaoOverride = qimaoMap[lenAnswer] || { channel: 'all', type: 'all' };
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
// 执行采集,包含 Chromium 缺失处理
|
|
94
115
|
const scanResult = await runScanWithChromiumFix(ctx, session, invocation, {
|
|
95
|
-
platform, length, projectRoot,
|
|
116
|
+
platform, length, projectRoot, qimaoOverride: ctx._qimaoOverride || null,
|
|
96
117
|
});
|
|
97
118
|
|
|
98
119
|
if (scanResult === 'retry') {
|
|
@@ -112,14 +133,19 @@ export async function apply(ctx) {
|
|
|
112
133
|
* 执行采集,检测 Chromium 缺失则提示用户手动安装。
|
|
113
134
|
* 返回 undefined 表示已处理完毕(取消/失败),返回 'retry' 表示重试完成。
|
|
114
135
|
*/
|
|
115
|
-
async function runScanWithChromiumFix(ctx, session, invocation, { platform, length, projectRoot }) {
|
|
136
|
+
async function runScanWithChromiumFix(ctx, session, invocation, { platform, length, projectRoot, qimaoOverride = null }) {
|
|
116
137
|
const runOnce = async (isRetry = false) => {
|
|
117
138
|
const stop = startActivity(session);
|
|
118
139
|
if (isRetry) notify(session, '⏳ 重新采集...\n');
|
|
140
|
+
const extraArgs = [];
|
|
141
|
+
if (platform === 'qimao' && qimaoOverride) {
|
|
142
|
+
extraArgs.push('--channel', qimaoOverride.channel, '--type', qimaoOverride.type);
|
|
143
|
+
}
|
|
119
144
|
const r = await spawnScript(
|
|
120
145
|
'node',
|
|
121
146
|
[join(SCAN_SCRIPTS_DIR, 'run-scan.js'),
|
|
122
|
-
'--project-root', projectRoot, '--platform', platform, '--length', length
|
|
147
|
+
'--project-root', projectRoot, '--platform', platform, '--length', length,
|
|
148
|
+
...extraArgs],
|
|
123
149
|
{ timeout: 900000, stop }
|
|
124
150
|
);
|
|
125
151
|
return r;
|
|
@@ -28,7 +28,7 @@ const PLATFORM_SUPPORTED_LENGTHS = {
|
|
|
28
28
|
fanqie: ['long'],
|
|
29
29
|
jinjiang: ['long'],
|
|
30
30
|
zhihu: ['long', 'short'],
|
|
31
|
-
qimao: ['long'
|
|
31
|
+
qimao: ['long'],
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
const PLATFORM_CN = {
|
|
@@ -163,10 +163,10 @@ function renderQidianMarkdown(rankLabel, url, books) {
|
|
|
163
163
|
// Browser scraper spawner(调用 scripts/scrapers/ 下的 CJS 脚本)
|
|
164
164
|
// ---------------------------------------------------------------------------
|
|
165
165
|
|
|
166
|
-
function spawnScraper(platform, length, outDir) {
|
|
166
|
+
function spawnScraper(platform, length, outDir, channel, type) {
|
|
167
167
|
return new Promise(async (resolve) => {
|
|
168
168
|
const { spawn } = await import('child_process');
|
|
169
|
-
const args = scraperArgs(platform, length, outDir);
|
|
169
|
+
const args = scraperArgs(platform, length, outDir, channel, type);
|
|
170
170
|
const scraperScript = join(dirname(fileURLToPath(import.meta.url)), 'scrapers', args.script);
|
|
171
171
|
const fullArgs = [...args.extra];
|
|
172
172
|
|
|
@@ -191,7 +191,7 @@ function spawnScraper(platform, length, outDir) {
|
|
|
191
191
|
});
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
function scraperArgs(platform, length, outDir) {
|
|
194
|
+
function scraperArgs(platform, length, outDir, channel, type) {
|
|
195
195
|
switch (platform) {
|
|
196
196
|
case 'fanqie':
|
|
197
197
|
return {
|
|
@@ -212,9 +212,8 @@ function scraperArgs(platform, length, outDir) {
|
|
|
212
212
|
case 'qimao':
|
|
213
213
|
return {
|
|
214
214
|
script: 'qimao-rank-scraper.cjs',
|
|
215
|
-
extra: ['--outdir', outDir],
|
|
215
|
+
extra: ['--channel', channel || 'all', '--type', type || 'all', '--outdir', outDir],
|
|
216
216
|
};
|
|
217
|
-
return { script: null, extra: [] };
|
|
218
217
|
default:
|
|
219
218
|
return { script: null, extra: [] };
|
|
220
219
|
}
|
|
@@ -316,12 +315,14 @@ function appendTopicDecision(platform, length, reportFile, outDir) {
|
|
|
316
315
|
|
|
317
316
|
async function main() {
|
|
318
317
|
const args = process.argv.slice(2);
|
|
319
|
-
let projectRoot = '', platform = '', length = '';
|
|
318
|
+
let projectRoot = '', platform = '', length = '', channel = '', type = '';
|
|
320
319
|
|
|
321
320
|
for (let i = 0; i < args.length; i++) {
|
|
322
321
|
if (args[i] === '--project-root') projectRoot = args[i + 1] || '';
|
|
323
322
|
if (args[i] === '--platform') platform = args[i + 1] || '';
|
|
324
323
|
if (args[i] === '--length') length = args[i + 1] || '';
|
|
324
|
+
if (args[i] === '--channel') channel = args[i + 1] || 'all';
|
|
325
|
+
if (args[i] === '--type') type = args[i + 1] || 'all';
|
|
325
326
|
}
|
|
326
327
|
|
|
327
328
|
if (!projectRoot || !platform || !length) {
|
|
@@ -373,7 +374,7 @@ async function main() {
|
|
|
373
374
|
process.exit(1);
|
|
374
375
|
}
|
|
375
376
|
console.error(`→ 采集 ${PLATFORM_CN[platform]}...`);
|
|
376
|
-
const result = await spawnScraper(platform, length, scanDir);
|
|
377
|
+
const result = await spawnScraper(platform, length, scanDir, channel, type);
|
|
377
378
|
if (!result.ok) {
|
|
378
379
|
console.error(` ❌ ${PLATFORM_CN[platform]} 采集失败:${result.error}`);
|
|
379
380
|
process.exit(1);
|
|
@@ -37,6 +37,19 @@ export const scan = {
|
|
|
37
37
|
},
|
|
38
38
|
|
|
39
39
|
askLength(platform) {
|
|
40
|
+
if (platform === 'qimao') {
|
|
41
|
+
return {
|
|
42
|
+
question: `七猫同时支持男频/女频、大热榜/新书榜,请选择采集范围:`,
|
|
43
|
+
hideCustomInput: true,
|
|
44
|
+
options: [
|
|
45
|
+
{ label: '采集全部(男/女 × 大热/新书,4个榜单)' },
|
|
46
|
+
{ label: '男生大热榜' },
|
|
47
|
+
{ label: '男生新书榜' },
|
|
48
|
+
{ label: '女生大热榜' },
|
|
49
|
+
{ label: '女生新书榜' },
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
40
53
|
return {
|
|
41
54
|
question: `${platformLabel(platform)} 同时支持长篇和短篇,请选择:`,
|
|
42
55
|
hideCustomInput: true,
|