@cloud411716/fancy-webnovel 0.1.49 → 0.1.51

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud411716/fancy-webnovel",
3
- "version": "0.1.49",
3
+ "version": "0.1.51",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -178,11 +178,16 @@ function spawnScraper(platform, length, outDir) {
178
178
  const args = scraperArgs(platform, length, outDir);
179
179
  const ports = ['9222', '9223'];
180
180
  let portIdx = 0;
181
+ let dots = 0;
182
+ const interval = setInterval(() => {
183
+ dots++;
184
+ process.stderr.write('.');
185
+ }, 3000);
181
186
 
182
187
  function tryPort(port) {
188
+ process.stderr.write(`\n → 端口 ${port} ...`);
183
189
  const scraperScript = join(dirname(fileURLToPath(import.meta.url)), 'scrapers', args.script);
184
190
  const fullArgs = ['--port', port, ...args.extra];
185
- // stderr 透传到父进程 stderr,用户实时看到进度
186
191
  const p = spawn('node', [scraperScript, ...fullArgs], {
187
192
  timeout: 120000,
188
193
  stdio: ['ignore', 'pipe', 'inherit'],
@@ -190,20 +195,27 @@ function spawnScraper(platform, length, outDir) {
190
195
  let out = '';
191
196
  p.stdout.on('data', d => { out += d.toString(); });
192
197
  p.on('close', (code) => {
198
+ clearInterval(interval);
193
199
  if (code === 0 && out.trim()) {
194
200
  resolve({ ok: true, output: out, stderr: '' });
195
201
  } else if (portIdx < ports.length - 1) {
196
202
  portIdx++;
203
+ process.stderr.write(` (失败)\n`);
197
204
  tryPort(ports[portIdx]);
198
205
  } else {
199
- // 截取 stderr 末尾 300 字符,避免过长
206
+ process.stderr.write(` (失败)\n`);
200
207
  const errTail = out.trimEnd().slice(-300);
201
208
  resolve({ ok: false, output: out, error: errTail || `exit ${code}` });
202
209
  }
203
210
  });
204
211
  p.on('error', (e) => {
205
- if (portIdx < ports.length - 1) { portIdx++; tryPort(ports[portIdx]); }
206
- else resolve({ ok: false, output: '', error: e.message });
212
+ clearInterval(interval);
213
+ if (portIdx < ports.length - 1) {
214
+ portIdx++;
215
+ tryPort(ports[portIdx]);
216
+ } else {
217
+ resolve({ ok: false, output: '', error: e.message });
218
+ }
207
219
  });
208
220
  }
209
221
  tryPort(ports[portIdx]);
@@ -88,8 +88,6 @@ function buildBookListJS() {
88
88
  }
89
89
  return list.map(function(b){return {
90
90
  bookId:String(b.bookId||b.book_id||''),
91
- title:b.bookName||b.book_name||b.title||b.name||'',
92
- author:b.authorName||b.author_name||b.author||'',
93
91
  read_count:b.read_count||b.readCount||b.read||'',
94
92
  wordNumber:b.wordNumber||b.word_number||b.wordCount||'',
95
93
  creationStatus:(b.creationStatus!=null?b.creationStatus:(b.creation_status!=null?b.creation_status:b.status)),
@@ -316,31 +314,40 @@ function scrapeChannel(ch, type) {
316
314
  }
317
315
  if (books.length > TOP) books = books.slice(0, TOP);
318
316
 
319
- // 直接用列表页数据,跳过详情页(字体反爬导致详情页不可靠)
320
- // const bookIds = books.map((b) => String(b.bookId));
321
- // const details = fetchDetails(PORT, bookIds);
317
+ // 分批解码真实书名/作者/简介/题材/评分/标签
318
+ const bookIds = books.map((b) => String(b.bookId));
319
+ const details = fetchDetails(PORT, bookIds);
322
320
 
323
321
  bodyLines.push(`## ${cat.name} — ${books.length} 本`, "");
324
322
 
325
323
  for (let i = 0; i < books.length; i++) {
326
324
  const b = books[i];
327
- // const info = details[String(b.bookId)] || {};
325
+ const info = details[String(b.bookId)] || {};
328
326
  totalBooks++;
329
- const resolved = !!b.title;
327
+ const resolved = !!info.title;
330
328
  if (resolved) resolvedTitles++;
331
329
 
332
- const title = b.title || "(标题待解析)";
333
- const author = b.author || "未知";
334
- const category = b.category || "";
330
+ const title = info.title || "(标题待解析)";
331
+ const author = info.author || "未知";
332
+ const category = info.category || b.category || "";
335
333
  const catSeg = category ? ` · ${category}` : "";
336
334
 
337
335
  bodyLines.push(`### #${i + 1} ${title}`);
338
336
  bodyLines.push(
339
337
  `*${author}${catSeg} · ${fmtStatus(b.creationStatus)} · ${fmtReads(b.read_count)} 在读 · ${fmtWords(b.wordNumber)}字*`
340
338
  );
339
+ if (info.tags) bodyLines.push(`**标签:** ${info.tags}`);
341
340
  bodyLines.push(`**最新更新:** ${b.lastChapterTitle || "未知"}`);
342
341
  bodyLines.push(`**bookId:** ${b.bookId}`);
342
+ if (info.err) bodyLines.push(`⚠️ 详情:${info.err}`);
343
343
  bodyLines.push(`[作品页](https://fanqienovel.com/page/${b.bookId})`);
344
+ const desc = cleanDesc(info.desc);
345
+ if (desc) {
346
+ bodyLines.push("");
347
+ bodyLines.push("**简介**");
348
+ bodyLines.push("");
349
+ bodyLines.push(desc);
350
+ }
344
351
  bodyLines.push("");
345
352
  }
346
353