126小说网

https://www.tatays.com

ethereal-essence (13554) 16小时前 下载:295

小说 免费 小说 免费小说
126小说网(tatays.com),免费网文小说站。
二维码导入(APP尚未完成该功能)
// @uuid        019e120b-d8e9-7212-abbc-5aecf0ddd257
// @name        126小说网
// @version     1.0.0
// @author      Ethereal
// @url         https://www.tatays.com
// @type        novel
// @logo        https://www.tatays.com/favicon.ico
// @enabled     true
// @tags        免费,小说,免费小说
// @description 126小说网(tatays.com),免费网文小说站。

// ─── 内置测试 ─────────────────────────────────────────────────────────────

async function TEST(type) {
  if (type === '__list__') return ['search', 'explore', 'bookInfo', 'chapterList', 'chapterContent'];

  if (type === 'search') {
    var results = await search('斗破苍穹', 1);
    if (!results || results.length < 1) return { passed: false, message: '搜索结果为空' };
    var found = false;
    for (var i = 0; i < results.length; i++) {
      if (results[i].author && results[i].author.indexOf('天蚕土豆') !== -1) { found = true; break; }
    }
    if (!found) return { passed: false, message: '搜索结果中未找到作者包含"天蚕土豆"的条目' };
    return { passed: true, message: '搜索"斗破苍穹"返回 ' + results.length + ' 条结果 ✓' };
  }

  if (type === 'explore') {
    var books = await explore(1, '玄幻奇幻');
    if (!books || books.length < 1) return { passed: false, message: '发现页 [玄幻奇幻] 返回为空' };
    return { passed: true, message: '发现页 [玄幻奇幻]: ' + books.length + ' 条结果 ✓' };
  }

  if (type === 'bookInfo') {
    var r = await bookInfo('https://www.tatays.com/book/109/');
    return { passed: !!r.name, message: 'bookInfo name=' + r.name + ' author=' + r.author };
  }

  if (type === 'chapterList') {
    var r = await chapterList('https://www.tatays.com/book/109/');
    return { passed: r.length > 0, message: 'chapterList cnt=' + r.length + ' first=' + (r[0] ? r[0].name : 'N/A') };
  }

  if (type === 'chapterContent') {
    var r = await chapterContent('https://www.tatays.com/book/109/224613.html');
    return { passed: r.length > 100, message: 'chapterContent len=' + r.length + ' first=' + r.substring(0, 40) };
  }

  return { passed: false, message: '未知测试类型: ' + type };
}

// ─── 配置 ────────────────────────────────────────────────────────────────

var BASE = 'https://www.tatays.com';

// ─── 工具 ────────────────────────────────────────────────────────────────

function toAbs(href) {
  if (!href) return '';
  if (href.indexOf('http') === 0) return href;
  return BASE + (href.charAt(0) === '/' ? href : '/' + href);
}

function extractCover(el, selector) {
  return legado.dom.selectAttr(el, selector, 'src') || '';
}

/** 目录 tocUrl 规范为作品页根路径 …/book/id/ */
function normalizeBookTocUrl(tocUrl) {
  var u = tocUrl;
  if (!u) return u;
  if (u.indexOf('http') !== 0) u = toAbs(u);
  var q = u.indexOf('?');
  if (q !== -1) u = u.substring(0, q);
  u = u.replace(/\/\d+s\.html\/?$/i, '/');
  if (u.charAt(u.length - 1) !== '/') u = u + '/';
  return u;
}

/** 从目录区 HTML 解析分页总数:…/book/id/Ns.html 与 kbd 内 当前/共 */
function extractChapterListMaxPage(html) {
  var maxP = 1;
  var re = /\/book\/\d+\/(\d+)s\.html/g;
  var m;
  while ((m = re.exec(html)) !== null) {
    var n = parseInt(m[1], 10);
    if (!isNaN(n) && n > maxP) maxP = n;
  }
  if (maxP === 1) {
    var kbd = html.match(/<kbd>[\s\S]*?<\/kbd>/i);
    if (kbd) {
      var frac = kbd[0].match(/(\d+)\s*\/\s*(\d+)/);
      if (frac) {
        var t = parseInt(frac[2], 10);
        if (!isNaN(t) && t > maxP) maxP = t;
      }
    }
  }
  return maxP;
}

function appendChaptersFromHtml(html, chapters, seenUrls) {
  var doc = legado.dom.parse(html);
  var links = legado.dom.selectAll(doc, '.chapter-box .chapter-list.clears a');
  for (var i = 0; i < links.length; i++) {
    var href = legado.dom.attr(links[i], 'href') || '';
    if (!href || href.indexOf('javascript') !== -1) continue;
    var chUrl = toAbs(href);
    var chName = (legado.dom.text(links[i]) || '').trim();
    if (chName && chUrl && !seenUrls[chUrl]) {
      seenUrls[chUrl] = 1;
      chapters.push({ name: chName, url: chUrl });
    }
  }
  legado.dom.free(doc);
}

// ─── 搜索 ─────────────────────────────────────────────────────────────────

async function search(keyword, page) {
  legado.log('[search] keyword=' + keyword + ' page=' + page);

  // 126小说网搜索使用 POST
  var url = BASE + '/modules/article/search.php';
  var p = page > 0 ? page : 1;
  var body = 'searchtype=all&searchkey=' + encodeURIComponent(keyword) + '&page=' + p;
  var html = await legado.http.post(url, body, {
    'Content-Type': 'application/x-www-form-urlencoded',
  });
  var doc = legado.dom.parse(html);
  var books = [];

  // 搜索结果在 .sort-list.search_words li 中(跳过第一个表头行)
  var items = legado.dom.selectAll(doc, '.sort-list.search_words li');
  for (var i = 1; i < items.length; i++) {
    var el = items[i];

    var bookUrl = legado.dom.selectAttr(el, '.one a', 'href');
    if (!bookUrl) continue;
    bookUrl = toAbs(bookUrl);

    var name = legado.dom.selectText(el, '.one a');
    if (!name) continue;

    var author = (legado.dom.selectText(el, '.three') || '').trim();
    var lastChapter = legado.dom.selectText(el, '.two a') || '';

    books.push({
      name: name,
      author: author,
      bookUrl: bookUrl,
      coverUrl: '',
      lastChapter: lastChapter,
      kind: '',
    });
  }

  legado.dom.free(doc);

  // 搜索列表无可用封面图,与各书详情页一致:从详情页取 .chapter-img img
  if (books.length > 0) {
    var detailUrls = [];
    for (var u = 0; u < books.length; u++) detailUrls.push(books[u].bookUrl);
    var batch = await legado.http.batchGet(detailUrls);
    var htmlByUrl = {};
    for (var bi = 0; bi < batch.length; bi++) {
      var br = batch[bi];
      if (br.ok && br.data) htmlByUrl[br.url] = br.data;
    }
    for (var bk = 0; bk < books.length; bk++) {
      var pageHtml = htmlByUrl[books[bk].bookUrl];
      if (!pageHtml && bk < batch.length && batch[bk].ok && batch[bk].data) {
        pageHtml = batch[bk].data;
      }
      if (!pageHtml) continue;
      var cdoc = legado.dom.parse(pageHtml);
      books[bk].coverUrl = extractCover(cdoc, '.chapter-img img');
      legado.dom.free(cdoc);
    }
  }

  legado.log('[search] found=' + books.length);
  return books;
}

// ─── 书籍详情 ─────────────────────────────────────────────────────────────

async function bookInfo(bookUrl) {
  legado.log('[bookInfo] url=' + bookUrl);
  var html = await legado.http.get(bookUrl);
  var doc = legado.dom.parse(html);

  var name = legado.dom.selectText(doc, '.chapter-list-info .mid h2');
  var coverUrl = extractCover(doc, '.chapter-img img');
  var intro = legado.dom.selectText(doc, '.info .intro');
  var lastChapter = legado.dom.selectText(doc, '.lastchapter a');

  // 详情信息在 .mid .clearfix dd 中
  var author = '';
  var kind = '';
  var ddEls = legado.dom.selectAll(doc, '.mid .clearfix dd');
  if (ddEls) {
    for (var i = 0; i < ddEls.length; i++) {
      var ddText = (legado.dom.text(ddEls[i]) || '').trim();
      if (ddText.indexOf('作者') !== -1) {
        var am = ddText.match(/作者[::]\s*(\S+)/);
        if (am) author = am[1];
      }
      if (ddText.indexOf('类型') !== -1) {
        kind = ddText.replace(/类型[::]\s*/, '').trim();
      }
    }
  }

  var result = {
    name: name,
    author: author,
    coverUrl: coverUrl,
    intro: intro,
    lastChapter: lastChapter,
    kind: kind,
    tocUrl: bookUrl,
  };

  legado.dom.free(doc);
  return result;
}

// ─── 章节列表 ─────────────────────────────────────────────────────────────

async function chapterList(tocUrl) {
  legado.log('[chapterList] url=' + tocUrl);
  var base = normalizeBookTocUrl(tocUrl);
  var html0 = await legado.http.get(base);
  var maxPage = extractChapterListMaxPage(html0);
  legado.log('[chapterList] pages=' + maxPage);

  var extraUrls = [];
  for (var pn = 2; pn <= maxPage; pn++) {
    extraUrls.push(base + pn + 's.html');
  }

  var batch = extraUrls.length ? await legado.http.batchGet(extraUrls) : [];

  var chapters = [];
  var seenUrls = {};
  appendChaptersFromHtml(html0, chapters, seenUrls);

  for (var bi = 0; bi < batch.length; bi++) {
    var br = batch[bi];
    if (br.ok && br.data) {
      appendChaptersFromHtml(br.data, chapters, seenUrls);
    }
  }

  legado.log('[chapterList] total=' + chapters.length);
  return chapters;
}

// ─── 正文 ─────────────────────────────────────────────────────────────────

async function chapterContent(chapterUrl) {
  legado.log('[content] url=' + chapterUrl);

  var html = await legado.http.get(chapterUrl);
  var doc = legado.dom.parse(html);

  var contentEl = legado.dom.select(doc, '.chapter-content');
  if (!contentEl) {
    legado.dom.free(doc);
    legado.log('[content] .chapter-content not found');
    return '';
  }

  var contentHtml = legado.dom.html(contentEl) || '';
  legado.dom.free(doc);

  var lines = contentHtml.split(/<br\s*\/?>|<\/?p[^>]*>/i);
  var paragraphs = [];
  for (var i = 0; i < lines.length; i++) {
    var text = lines[i].replace(/<[^>]+>/g, '').replace(/&nbsp;/g, ' ').replace(/\s+/g, ' ').trim();
    if (text && !/本章未完|加入书签|章节报错|126小说|tatays/.test(text)) {
      paragraphs.push(text);
    }
  }

  return paragraphs.join('\n\n');
}

// ─── 发现页 ──────────────────────────────────────────────────────────────

var EXPLORE_CATEGORIES = [
  { name: '玄幻奇幻', path: '/xuanhuan/p1.html' },
  { name: '武侠修真', path: '/wuxia/p1.html' },
  { name: '都市言情', path: '/yanqing/p1.html' },
  { name: '历史军事', path: '/lishi/p1.html' },
  { name: '科幻小说', path: '/kehuan/p1.html' },
  { name: '网游小说', path: '/wangyou/p1.html' },
  { name: '女生小说', path: '/nvsheng/p1.html' },
  { name: '其他小说', path: '/qita/p1.html' },
];

async function explore(page, category) {
  var cat = null;
  for (var i = 0; i < EXPLORE_CATEGORIES.length; i++) {
    if (EXPLORE_CATEGORIES[i].name === category) {
      cat = EXPLORE_CATEGORIES[i];
      break;
    }
  }
  if (!cat) return EXPLORE_CATEGORIES.map(function(c) { return c.name; });

  var pg = page > 0 ? page : 1;
  var path = cat.path.replace(/p1\.html$/, 'p' + pg + '.html');
  var url = BASE + path;
  var html = await legado.http.get(url);
  var doc = legado.dom.parse(html);
  var books = [];

  // 分类页用 .list-content .list-title li 结构
  var items = legado.dom.selectAll(doc, '.list-title li');
  for (var i = 0; i < items.length; i++) {
    var el = items[i];
    var bookUrl = legado.dom.selectAttr(el, 'a', 'href');
    if (!bookUrl) continue;
    bookUrl = toAbs(bookUrl);

    var name = legado.dom.selectText(el, 'h2');
    if (!name) continue;

    var coverUrl = extractCover(el, 'img');
    var authorLine = legado.dom.selectText(el, 'p.info');
    var authorM = authorLine.match(/作者[::]\s*([^|]+)/);
    var author = authorM ? authorM[1].trim() : '';

    books.push({ name: name, author: author, bookUrl: bookUrl, coverUrl: coverUrl });
  }

  legado.dom.free(doc);
  return books;
}
广告