@cloud411716/fancy-webnovel 0.2.20 → 0.2.22

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.2.20",
3
+ "version": "0.2.22",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -293,33 +293,28 @@ async function scrapeRank(rankTypeId, channelId) {
293
293
  "",
294
294
  `- 来源:${url}`,
295
295
  `- 抓取时间:${now}`,
296
+ `- 条目数:${totalBooks}`,
296
297
  "",
297
298
  "---",
298
299
  "",
299
300
  ];
300
301
 
301
302
  for (const ch of data.channels) {
302
- lines.push(`## ${ch.name}`, "");
303
- for (let i = 0; i < ch.books.length; i++) {
304
- const b = ch.books[i];
305
- lines.push(`书名:${b.title || ""}`);
306
- lines.push(`作者:${b.author || ""}`);
307
- if (data.layout === 'A') {
308
- // 布局A(表格型):已有丰富字段,直接使用
309
- if (b.type) lines.push(`类型:${b.type}`);
310
- if (b.progress) lines.push(`进度:${b.progress}`);
311
- if (b.words) lines.push(`字数:${b.words}`);
312
- if (b.score) lines.push(`积分:${b.score}`);
313
- if (b.pubtime) lines.push(`发表时间:${b.pubtime}`);
314
- lines.push(`题材:${b.type ? b.type.split('-')[1] || b.type : ""}`);
315
- } else {
316
- // 布局B(交替行型):只有书名/作者,其他留空让详情补采
317
- lines.push(`题材:${ch.name}`);
303
+ for (let i = 0; i < ch.books.length; i++) {
304
+ const b = ch.books[i];
305
+ var genre = '';
306
+ if (data.layout === 'A' && b.type) {
307
+ var parts = b.type.split('-');
308
+ genre = parts[1] || '';
309
+ } else {
310
+ genre = ch.name;
311
+ }
312
+ lines.push(`书名:${b.title || ""}`);
313
+ lines.push(`题材:${genre}`);
314
+ lines.push(`作者:${b.author || ""}`);
315
+ if (b.novelid) lines.push(`作品页:https://www.jjwxc.net/onebook.php?novelid=${b.novelid}`);
316
+ lines.push("");
318
317
  }
319
- if (b.novelid) lines.push(`作品页:https://www.jjwxc.net/onebook.php?novelid=${b.novelid}`);
320
- lines.push("");
321
- }
322
- lines.push("--", "");
323
318
  }
324
319
 
325
320
  return {
@@ -183,6 +183,7 @@ async function scrapeRank(channelId, rankTypeId, periodId) {
183
183
  if (!b.bookId && !b.novel_id && !b.id) continue;
184
184
  const id = String(b.bookId || b.novel_id || b.id);
185
185
  xhrBookMap.set(id, {
186
+ id: id,
186
187
  title: b.title || b.bookName || b.name || "",
187
188
  author: b.author || b.authorName || "",
188
189
  });
@@ -278,6 +279,28 @@ async function scrapeRank(channelId, rankTypeId, periodId) {
278
279
  rawCount = rawBooks.length;
279
280
  books = rawBooks.filter(isUsableBook);
280
281
 
282
+ // 直接从 DOM 提取 /shuku/{id}/ 链接补到每本书上(不依赖 XHR 匹配)
283
+ const urlMap = {};
284
+ await page.evaluate(() => {
285
+ document.querySelectorAll('a[href*="/shuku/"]').forEach(a => {
286
+ var m = a.href.match(/\/shuku\/(\d+)\//);
287
+ if (!m) return;
288
+ var id = m[1];
289
+ // 取离它最近的文字作为书名
290
+ var title = (a.innerText || '').trim();
291
+ if (title && title.length < 50 && title.length > 0) {
292
+ urlMap[title] = 'https://www.qimao.com/shuku/' + id + '/';
293
+ }
294
+ });
295
+ });
296
+ const norm = s => (s || '').replace(/\s+/g, '');
297
+ for (const b of books) {
298
+ if (!b.url) {
299
+ var found = Object.entries(urlMap).find(([t]) => norm(t) === norm(b.title));
300
+ if (found) b.url = found[1];
301
+ }
302
+ }
303
+
281
304
  // 用 XHR 数据覆盖明文书名/作者,绕过字体加密
282
305
  if (xhrBookMap.size > 0) {
283
306
  let updated = 0;