蚂蚁文学

https://www.mayiwsk.com/

zpccool (13551) 1天前 下载:408

小说
该用户很懒,什么介绍也没有写!
二维码导入(APP尚未完成该功能)
// @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(/&nbsp;/gi, ' ');
  s = s.replace(/&amp;/gi, '&');
  s = s.replace(/&lt;/gi, '<');
  s = s.replace(/&gt;/gi, '>');
  s = s.replace(/&#039;/gi, "'");
  s = s.replace(/&quot;/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);
  }
}
广告