126小说网
https://www.tatays.com
ethereal-essence (13554) 16小时前 下载:295
小说 免费 小说 免费小说
126小说网(tatays.com),免费网文小说站。
// @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(/ /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;
}