蚂蚁文学
https://www.mayiwsk.com/
zpccool (13551) 1天前 下载:408
小说
该用户很懒,什么介绍也没有写!
// @enabled true
// @name 蚂蚁文学
// @version 1.0.0
// @uuid mayiwenxue
// @author Ai
// @url https://www.mayiwsk.com/
// Legado Tauri 书源(ES5 / 同步)
var BASE = 'https://www.mayiwsk.com';
var CATEGORY_MAP = {
'玄幻小说': 'xuanhuanxiaoshuo',
'修真小说': 'xiuzhenxiaoshuo',
'都市小说': 'dushixiaoshuo',
'穿越小说': 'chuanyuexiaoshuo',
'网游小说': 'wangyouxiaoshuo',
'科幻小说': 'kehuanxiaoshuo',
'完本小说': 'wanben'
};
function _absUrl(url) {
if (!url) return '';
if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) return url;
if (url.charAt(0) === '/') return BASE + url;
return BASE + '/' + url;
}
function _trim(s) {
if (s == null) return '';
return ('' + s).replace(/^\s+|\s+$/g, '');
}
function _textOrEmpty(t) {
return _trim(t || '');
}
function _pickMeta(html, key) {
var re = new RegExp('<meta\\s+property=["\']' + key.replace(/\./g, '\\.') + '["\']\\s+content=["\']([\\s\\S]*?)["\']', 'i');
var m = (html || '').match(re);
return m && m[1] ? _trim(m[1]) : '';
}
function _guessCoverByBookUrl(bookUrl) {
// 规则:/kanshu/<dir>/<bookId>/ -> /files/article/image/<dir>/<bookId>/<bookId>s.jpg
var m = (bookUrl || '').match(/\/kanshu\/(\d+)\/(\d+)\/?$/i);
if (!m) return '';
return BASE + '/files/article/image/' + m[1] + '/' + m[2] + '/' + m[2] + 's.jpg';
}
function _normalizeCoverUrl(coverUrl) {
// 速度与稳定优先:直接使用站内真实封面直链
var raw = _absUrl(coverUrl || '');
if (!raw) return '';
// 某些书封面缺失会返回站点根地址,这里直接置空避免无效加载
if (raw === BASE || raw === BASE + '/') return '';
if (/\/images\/nopic\.gif$/i.test(raw)) return '';
return raw;
}
function _extractCoverFromDetailHtml(html) {
var og = _pickMeta(html, 'og:image');
var c1 = _normalizeCoverUrl(og);
if (c1) return c1;
var m = (html || '').match(/<img[^>]+(?:class=["'][^"']*imgbox[^"']*["'][^>]*|alt=["'][^"']*["'][^>]*?)src=["']([^"']+)["']/i);
if (m && m[1]) {
var c2 = _normalizeCoverUrl(m[1]);
if (c2) return c2;
}
return '';
}
function _pickCoverFast(rawCover, bookUrl) {
var c = _normalizeCoverUrl(rawCover);
if (c) return c;
return _normalizeCoverUrl(_guessCoverByBookUrl(bookUrl));
}
function _cleanHtmlToText(html) {
if (!html) return '';
var s = '' + html;
s = s.replace(/<script[\s\S]*?<\/script>/gi, '');
s = s.replace(/<style[\s\S]*?<\/style>/gi, '');
s = s.replace(/<br\s*\/?>/gi, '\n');
s = s.replace(/<\/p>/gi, '\n');
s = s.replace(/<p[^>]*>/gi, '');
s = s.replace(/ /gi, ' ');
s = s.replace(/&/gi, '&');
s = s.replace(/</gi, '<');
s = s.replace(/>/gi, '>');
s = s.replace(/'/gi, "'");
s = s.replace(/"/gi, '"');
s = s.replace(/<[^>]+>/g, '');
s = s.replace(/\r/g, '');
s = s.replace(/\n{3,}/g, '\n\n');
return _trim(s);
}
function _parseBookDetail(html, bookUrl) {
// 只走正则提取 meta,减少 DOM 解析耗时
var name = _pickMeta(html, 'og:novel:book_name');
var author = _pickMeta(html, 'og:novel:author');
var kind = _pickMeta(html, 'og:novel:category');
var status = _pickMeta(html, 'og:novel:status');
var updateTime = _pickMeta(html, 'og:novel:update_time');
var latestChapter = _pickMeta(html, 'og:novel:latest_chapter_name');
var intro = _cleanHtmlToText(_pickMeta(html, 'og:description'));
if (!name) {
var t = (html || '').match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
if (t && t[1]) name = _cleanHtmlToText(t[1]);
}
if (!author) {
var a = (html || '').match(/作者[::]\s*([^<\r\n]+)/i);
if (a && a[1]) author = _trim(a[1]);
}
return {
name: name,
author: author,
intro: intro,
coverUrl: _pickCoverFast(_extractCoverFromDetailHtml(html), bookUrl),
kind: kind,
status: status,
updateTime: updateTime,
latestChapter: latestChapter,
bookUrl: bookUrl,
tocUrl: bookUrl
};
}
async function search(keyword, page) {
legado.log('[search] keyword=' + keyword + ' page=' + page);
var url = BASE + '/modules/article/search.php?searchkey=' + encodeURIComponent(keyword) + '&searchtype=articlename&page=' + page;
var html = await legado.http.get(url);
var doc = legado.dom.parse(html);
try {
var rows = legado.dom.selectAll(doc, '#content tbody tr');
var out = [];
for (var i = 1; i < rows.length; i++) {
var row = rows[i];
var bookLink = legado.dom.select(row, '.odd a');
if (!bookLink) continue;
var bookInfoArray = legado.dom.selectAll(row, 'td');
var bookUrl = _absUrl(legado.dom.attr(bookLink, 'href'));
var name = _textOrEmpty(legado.dom.text(bookLink));
var kind = _textOrEmpty(legado.dom.selectText(row, '.s1'));
kind = kind.replace(/^\[|\]$/g, '').replace(/^\[|\]$/g, '');
var author = _textOrEmpty(legado.dom.text(bookInfoArray[2]));
var latest = _textOrEmpty(legado.dom.selectText(row, '.even a'));
out.push({
name: name,
bookUrl: bookUrl,
author: author,
coverUrl: _pickCoverFast('', bookUrl),
intro: '',
latestChapter: latest,
kind: kind
});
}
legado.log('[search] found=' + out.length);
return out;
} finally {
legado.dom.free(doc);
}
}
async function bookInfo(bookUrl) {
legado.log('[bookInfo] bookUrl=' + bookUrl);
var html = await legado.http.get(bookUrl);
return _parseBookDetail(html, bookUrl);
}
async function chapterList(tocUrl) {
legado.log('[chapterList] tocUrl=' + tocUrl);
var html = await legado.http.get(tocUrl);
var doc = legado.dom.parse(html);
try {
// 目录分页在 select[name=pageselect] option[value]
var pageUrls = legado.dom.selectAllAttrs(doc, 'select[name="pageselect"] option', 'value');
var urls = [];
for (var i = 0; i < pageUrls.length; i++) {
var u = _absUrl(pageUrls[i]);
if (!u) continue;
urls.push(u);
}
if (urls.length === 0) urls = [tocUrl];
var chapters = [];
var htmlMap = {};
htmlMap[urls[0]] = html;
// 并发拉取剩余目录分页(首个分页已复用)
if (urls.length > 1) {
var restUrls = [];
for (var r = 1; r < urls.length; r++) restUrls.push(urls[r]);
var batch = null;
try {
// 某些安卓阅读器实现中 batchGet 可能不存在或返回结构不同
batch = await legado.http.batchGet(restUrls, null, 8);
} catch (e) {
batch = null;
}
if (batch && batch.length) {
for (var b = 0; b < restUrls.length; b++) {
var one = batch[b];
var body = '';
if (typeof one === 'string') {
body = one;
} else if (one && typeof one === 'object') {
// 兼容不同实现:可能是 { body } / { data } / { content }
body = one.body || one.data || one.content || '';
}
htmlMap[restUrls[b]] = body || '';
}
} else {
// batchGet 异常时降级串行,避免目录空白
for (var f = 0; f < restUrls.length; f++) {
htmlMap[restUrls[f]] = await legado.http.get(restUrls[f]);
}
}
}
for (var p = 0; p < urls.length; p++) {
var pageHtml = htmlMap[urls[p]] || '';
if (!pageHtml) continue;
var pageDoc = legado.dom.parse(pageHtml);
try {
var all = legado.dom.selectAll(pageDoc, '#list dl');
const ddArray=[]
for(item in all){
if(item.tagName==='DT' && item.textContent.includes('正文')){
ddArray=[]
continue;
}
ddArray.push(item)
}
// “正文”
var links = legado.dom.selectAll(pageDoc, '#list dt:nth-of-type(2) ~ dd a');
if (!links) continue;
for (var j = 0; j < links.length; j++) {
var a = links[j];
var href = _absUrl(legado.dom.attr(a, 'href'));
var title = _textOrEmpty(legado.dom.text(a));
if (!href || !title) continue;
chapters.push({
name: title,
url: href
});
}
} finally {
legado.dom.free(pageDoc);
}
}
legado.log('[chapterList] chapters=' + chapters.length);
return chapters;
} finally {
legado.dom.free(doc);
}
}
function _extractTotalPagesFromContentText(text) {
// 例:第21章 整合势力 (第1/3页)
var m = (text || '').match(/\(第\s*\d+\s*\/\s*(\d+)\s*页\)/);
if (m && m[1]) {
var n = parseInt(m[1], 10);
if (!isNaN(n) && n > 0 && n < 50) return n;
}
return 1;
}
function _normalizeChapterBaseUrl(chapterUrl) {
// /123.html 或 /123_2.html
return (chapterUrl || '').replace(/_(\d+)\.html(\?.*)?$/i, '.html');
}
async function chapterContent(chapterUrl) {
legado.log('[chapterContent] chapterUrl=' + chapterUrl);
var baseUrl = _normalizeChapterBaseUrl(chapterUrl);
var firstHtml = await legado.http.get(baseUrl);
var firstDoc = legado.dom.parse(firstHtml);
var firstInner = '';
try {
var content = legado.dom.select(firstDoc, '#content')
var contentText = legado.dom.ownText(content)
// legado.log('[chapterContent] ownText=' + legado.dom.ownText(content));
var firstInner = contentText;
} finally {
legado.dom.free(firstDoc);
}
var full = firstInner;
// 小说书源必须返回纯文本字符串
return full;
}
async function explore(page, category) {
// category 可为 string / number / object
legado.log('[explore] init page=' + page + ' category=' + category);
var catId = '1';
if (category && typeof category === 'object') {
catId = '' + (category.id || category.value || category.key || '1');
} else if (category != null && category !== '') {
catId = '' + category;
}
// GETALL 必须返回分类字符串数组,否则安卓端会提示“没有发现分类”
if (catId === 'GETALL' || catId === 'ALL' || catId === 'all') {
legado.log('[explore] page=' + page + ' category=GETALL');
const categoryList=[];
for( key in CATEGORY_MAP){
categoryList.push(key)
}
return categoryList;
}
// 兼容安卓端传分类名
if (CATEGORY_MAP[catId]) catId = CATEGORY_MAP[catId];
legado.log('[explore] page=' + page + ' category=' + catId);
var url = BASE + '/' + catId ;
var html = await legado.http.get(url);
var doc = legado.dom.parse(html);
try {
var out = [];
var seen = {};
// 头部推荐块
var items = legado.dom.selectAll(doc, '#hotcontent .item');
for (var i = 0; i < items.length; i++) {
var it = items[i];
var a = legado.dom.select(it, 'dl dt a');
if (!a) continue;
var bookUrl = _absUrl(legado.dom.attr(a, 'href'));
if (!bookUrl || seen[bookUrl]) continue;
var name = _textOrEmpty(legado.dom.selectText(it, 'dl dt a'));
var author = _textOrEmpty(legado.dom.selectText(it, 'dl dt span'));
var intro = _textOrEmpty(legado.dom.selectText(it, 'dl dd'));
var coverUrl = _textOrEmpty(legado.dom.selectAttr(it, 'img', 'src'));
coverUrl = _pickCoverFast(coverUrl, bookUrl);
seen[bookUrl] = 1;
out.push({
name: name,
bookUrl: bookUrl,
author: author,
coverUrl: coverUrl,
intro: intro,
kind: '',
latestChapter: ''
});
}
// 最近更新列表
var rows = legado.dom.selectAll(doc, '#newscontent ul li');
for (var j = 0; j < rows.length; j++) {
var row = rows[j];
var bookLink = legado.dom.select(row, '.s2 a');
if (!bookLink) continue;
var bUrl = _absUrl(legado.dom.attr(bookLink, 'href'));
if (!bUrl || seen[bUrl]) continue;
var bName = _textOrEmpty(legado.dom.text(bookLink));
var bAuthor = _textOrEmpty(legado.dom.selectText(row, '.s5'));
var bLatest = _textOrEmpty(legado.dom.selectText(row, '.s3 a'));
var bKind = _textOrEmpty(legado.dom.selectText(row, '.s1'));
bKind = bKind.replace(/^\[|\]$/g, '').replace(/^\[|\]$/g, '');
seen[bUrl] = 1;
out.push({
name: bName,
bookUrl: bUrl,
author: bAuthor,
coverUrl: _pickCoverFast('', bUrl),
intro: '',
kind: bKind,
latestChapter: bLatest
});
}
legado.log('[explore] found=' + out.length);
return out;
} finally {
legado.dom.free(doc);
}
}