奇书网

https://www.qishu33.com

zpccool (13551) 16小时前 下载:303

小说 小说 免费
奇书网 - 好看的小说大全免费在线阅读和txt下载。
二维码导入(APP尚未完成该功能)
// @name        奇书网
// @uuid        qishu
// @version     1.0.0
// @author      AI
// @url         https://www.qishu33.com
// @type        novel
// @enabled     true
// @tags        小说,免费
// @description 奇书网 - 好看的小说大全免费在线阅读和txt下载。

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

var CATEGORIES = [
  { title: '玄幻', id: '1' },
  { title: '仙侠', id: '2' },
  { title: '都市', id: '3' },
  { title: '职场', id: '4' },
  { title: '历史', id: '5' },
  { title: '军事', id: '6' },
  { title: '科幻', id: '7' },
  { title: '游戏', id: '8' },
  { title: '灵异', id: '9' },
  { title: '乡村', id: '10' },
  { title: '现言', id: '11' },
  { title: '古言', id: '12' },
  { title: '穿越', id: '13' },
  { title: '总裁', id: '14' },
  { title: '浪漫', id: '15' },
  { title: '耽美', id: '16' }
];

function absUrl(url, baseUrl) {
  if (!url) return '';
  if (url.indexOf('http') === 0) return url;
  if (url.indexOf('//') === 0) return 'https:' + url;
  if (url.indexOf('/') === 0) return BASE + url;
  var base = baseUrl || BASE;
  var lastSlash = base.lastIndexOf('/');
  if (lastSlash <= 7) return base + '/' + url;
  return base.substring(0, lastSlash + 1) + url;
}

var DEFAULT_HEADERS = {
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
  'Accept': 'text/html,application/xhtml+xml',
  'Accept-Language': 'zh-CN,zh;q=0.9',
  'Referer': BASE
};

// ─── 解析书籍 ─────────────────────────────────────────────────────────
function parseBooks(html, defaultKind) {
  var books = [];
  var seen = {};
  var items = html.match(/<div\s+class=["']item["'][^>]*>([\s\S]*?)<\/div>\s*<\/div>/gi);
  if (items && items.length > 0) {
    for (var i = 0; i < items.length; i++) {
      var itemHtml = items[i];
      var linkMatch = itemHtml.match(/href=["']([^"']*\/xiaoshuo\/\d+[^"']*)["'][^>]*>\s*<[^>]*>([^<]*)/i);
      if (linkMatch) {
        var bookUrl = absUrl(linkMatch[1]);
        var name = linkMatch[2].replace(/^《|》$/g, '').trim();
        if (!name) { var nm2 = itemHtml.match(/<h[23][^>]*>([^<]+)/); if (nm2) name = nm2[1].replace(/^《|》$/g, '').trim(); }
        if (name && bookUrl && !seen[bookUrl]) {
          seen[bookUrl] = true;
          var am = itemHtml.match(/作者[::]\s*([^<\n]+)/);
          books.push({ name: name, author: am ? am[1].trim() : '', bookUrl: bookUrl, coverUrl: '', kind: defaultKind || '', lastChapter: '' });
        }
      }
    }
    if (books.length > 0) return books;
  }
  var linkPattern = /href=["']([^"']*\/xiaoshuo\/(\d+)[^"']*)["'][^>]*>([^<]+)<\/a>/gi;
  var match;
  while ((match = linkPattern.exec(html)) !== null) {
    var bookUrl2 = absUrl(match[1]);
    var name2 = match[3].replace(/^《|》$/g, '').trim();
    if (!name2 || name2.indexOf('章') !== -1 || name2.indexOf('节') !== -1) continue;
    if (bookUrl2.indexOf('/xiaoshuo/') === -1) continue;
    if (!seen[bookUrl2]) {
      seen[bookUrl2] = true;
      books.push({ name: name2, author: '', bookUrl: bookUrl2, coverUrl: '', kind: defaultKind || '', lastChapter: '' });
    }
  }
  return books;
}

// ─── 解析书籍详情 ─────────────────────────────────────────────────────
function parseBookInfo(html) {
  var result = { name: '', author: '', coverUrl: '', intro: '', kind: '', lastChapter: '' };
  var metas = [
    { key: 'name', pat: /<meta\s+property=["']og:novel:book_name["']\s+content=["']([^"']+)["']/i },
    { key: 'name', pat: /<meta\s+property=["']og:title["']\s+content=["']([^"']+)["']/i },
    { key: 'author', pat: /<meta\s+property=["']og:novel:author["']\s+content=["']([^"']+)["']/i },
    { key: 'coverUrl', pat: /<meta\s+property=["']og:image["']\s+content=["']([^"']+)["']/i },
    { key: 'intro', pat: /<meta\s+name=["']description["']\s+content=["']([^"']+)["']/i },
    { key: 'kind', pat: /<meta\s+property=["']og:novel:category["']\s+content=["']([^"']+)["']/i },
    { key: 'lastChapter', pat: /<meta\s+property=["']og:novel:latest_chapter_name["']\s+content=["']([^"']+)["']/i }
  ];
  for (var i = 0; i < metas.length; i++) {
    if (result[metas[i].key]) continue;
    var m = html.match(metas[i].pat);
    if (m && m[1]) result[metas[i].key] = m[1];
  }
  if (!result.author) { var am = html.match(/作者[::]\s*([^<"\n]+)/); if (am) result.author = am[1].trim(); }
  if (!result.intro) { var im = html.match(/简介[::]\s*([^\n<]+)/); if (im) result.intro = im[1].trim(); }
  if (!result.lastChapter) { var cm = html.match(/最新章节[::]?\s*\[([^\]]+)\]/); if (cm) result.lastChapter = cm[1]; }
  if (!result.name) result.name = '未知书名';
  if (!result.author) result.author = '未知作者';
  return result;
}

// ─── 搜索 ─────────────────────────────────────────────────────────────
async function search(keyword, page) {
  try {
    if (!keyword) return [];
    legado.log('[search] keyword=' + keyword);
    var encoded = await legado.urlEncodeCharset(keyword, 'utf-8');
    var searchUrl = BASE + '/search.html?searchkey=' + encoded;
    if (page && page > 1) searchUrl += '&page=' + page;
    var html = await legado.http.get(searchUrl, DEFAULT_HEADERS);
    var books = parseBooks(html, '');
    legado.log('[search] found ' + books.length);
    return books;
  } catch (e) { legado.log('[search] error: ' + e); return []; }
}

// ─── 发现页 ────────────────────────────────────────────────────────────
async function explore(page, category) {
  try {
    if (category === 'GETALL' || !category) {
      var names = [];
      for (var i = 0; i < CATEGORIES.length; i++) names.push(CATEGORIES[i].title);
      return names;
    }
    var catId = null;
    for (var j = 0; j < CATEGORIES.length; j++) {
      if (CATEGORIES[j].title === category) { catId = CATEGORIES[j].id; break; }
    }
    if (!catId) return [];
    var url = BASE + '/type/' + catId + '_0_0_lastupdate_' + (page || 1) + '.html';
    var html = await legado.http.get(url, DEFAULT_HEADERS);
    return parseBooks(html, category);
  } catch (e) { legado.log('[explore] error: ' + e); return []; }
}

// ─── 书籍详情 ─────────────────────────────────────────────────────────
async function bookInfo(bookUrl) {
  try {
    var url = absUrl(bookUrl);
    var html = await legado.http.get(url, DEFAULT_HEADERS);
    var info = parseBookInfo(html);
    return {
      name: info.name, author: info.author, bookUrl: url, tocUrl: url,
      coverUrl: absUrl(info.coverUrl), intro: info.intro,
      kind: info.kind, lastChapter: info.lastChapter
    };
  } catch (e) {
    return { name: '未知', author: '未知', bookUrl: bookUrl, tocUrl: bookUrl,
      coverUrl: '', intro: '', kind: '', lastChapter: '' };
  }
}

// ─── 章节列表 ─────────────────────────────────────────────────────────
async function chapterList(tocUrl) {
  try {
    var url = absUrl(tocUrl);
    legado.log('[chapterList] url=' + url);
    var html = await legado.http.get(url, DEFAULT_HEADERS);

    // bookId from URL
    var bookId = '';
    var idm = url.match(/\/xiaoshuo\/(\d+)/);
    if (idm) bookId = idm[1];

    // total chapters from paixu(ID, TOTAL)
    var totalCh = '';
    var pm = html.match(/paixu\(\d+,\s*(\d+)\)/);
    if (pm) totalCh = pm[1];

    legado.log('[chapterList] bookId=' + bookId + ' totalCh=' + totalCh);
    if (!bookId || !totalCh) { legado.log('[chapterList] missing params'); return []; }

    // 从书页 #toplist 解析前几章
    var chapters = [];
    var seen = {};
    var rePage = /href=["']([^"']*read_\d+\.html)["'][^>]*>([^<]*)<\/a>/gi;
    var mP;
    while ((mP = rePage.exec(html)) !== null) {
      var hrefP = mP[1];
      var textP = mP[2].trim();
      var ciP = textP.indexOf('第');
      var cleanP = ciP >= 0 ? textP.substring(ciP) : textP;
      cleanP = cleanP.replace(/^\s+/, '').replace(/\s+$/, '');
      if (cleanP.indexOf('第') !== -1 && cleanP.indexOf('章') !== -1) {
        var chUrlP = absUrl(hrefP, BASE);
        if (!seen[chUrlP]) { seen[chUrlP] = true; chapters.push({ name: cleanP, url: chUrlP }); }
      }
    }
    legado.log('[chapterList] from page: ' + chapters.length);

    // 获取剩余章节: /novelsearch/novel/getdlist/?id=ID&num=TOTAL&order=asc
    var api = BASE + '/novelsearch/novel/getdlist/?id=' + bookId + '&num=' + totalCh + '&order=asc';
    legado.log('[chapterList] api=' + api);
    var apiHtml = await legado.http.get(api, DEFAULT_HEADERS);
    legado.log('[chapterList] api response=' + (apiHtml ? apiHtml.length : 0));

    if (apiHtml && apiHtml.length >= 500) {
      var reApi = /href=["']([^"']*read_\d+\.html)["'][^>]*>([^<]*)<\/a>/gi;
      var mA;
      while ((mA = reApi.exec(apiHtml)) !== null) {
        var hrefA = mA[1];
        var textA = mA[2].trim();
        var ciA = textA.indexOf('第');
        var cleanA = ciA >= 0 ? textA.substring(ciA) : textA;
        cleanA = cleanA.replace(/^\s+/, '').replace(/\s+$/, '');
        if (cleanA.indexOf('第') !== -1 && cleanA.indexOf('章') !== -1) {
          var chUrlA = absUrl(hrefA, BASE);
          if (!seen[chUrlA]) { seen[chUrlA] = true; chapters.push({ name: cleanA, url: chUrlA }); }
        }
      }
    }
    // 按 read_N 数字排序
    chapters.sort(function(a, b) {
      var na = parseInt((a.url.match(/read_(\d+)/) || [0,0])[1], 10);
      var nb = parseInt((b.url.match(/read_(\d+)/) || [0,0])[1], 10);
      return na - nb;
    });

    legado.log('[chapterList] total=' + chapters.length);
    return chapters;
  } catch (e) { legado.log('[chapterList] error: ' + e); return []; }
}

// ─── 章节正文 ─────────────────────────────────────────────────────────
async function chapterContent(chapterUrl) {
  try {
    var url = absUrl(chapterUrl);
    var html = await legado.http.get(url, DEFAULT_HEADERS);
    var doc = legado.dom.parse(html);
    var contentEl = null;
    var sels = ['#content', '.content', '.chapter-content', '.book-content', '.xscontent', '.read-content', '#J_content'];
    for (var i = 0; i < sels.length; i++) {
      var el = legado.dom.select(doc, sels[i]);
      if (el && legado.dom.html(el).length > 200) { contentEl = el; break; }
    }
    if (!contentEl) contentEl = legado.dom.select(doc, 'body');
    legado.dom.remove(contentEl, 'script, style, .ad, .ads, .share');
    var hc = legado.dom.html(contentEl);
    legado.dom.free(doc);
    return processContent(hc);
  } catch (e) { legado.log('[content] error: ' + e); return ''; }
}

function processContent(htmlContent) {
  if (!htmlContent) return '';
  var t = htmlContent
    .replace(/<br\s*\/?>\s*<br\s*\/?>/gi, '{{P}}')
    .replace(/<br\s*\/?>/gi, '\n')
    .replace(/<[^>]+>/g, '')
    .replace(/\{\{P\}\}/g, '\n\n');
  t = t.replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, "'");
  t = t.replace(/上一章[\s\S]*?下一章/g, '').replace(/可以使用回车快捷键阅读[\s\S]*/g, '').replace(/记住网站域名[\s\S]*/g, '').replace(/天才一秒记住[\s\S]*/g, '').replace(/请收藏[\s\S]*/g, '').replace(/本章未完[\s\S]*/g, '').replace(/章节报错[\s\S]*/g, '');
  return t.replace(/[ \t]+/g, ' ').replace(/\n{3,}/g, '\n\n').trim();
}

// ─── 测试 ────────────────────────────────────────────────────────────
async function TEST(type) {
  if (type === '__list__') return ['search', 'explore', 'bookInfo', 'chapterList', 'chapterContent'];
  if (type === 'search') { var r = await search('斗破苍穹', 1); if (!r || r.length < 1) return { passed: false, message: '无结果' }; return { passed: true, message: '搜索' + r.length + '条' }; }
  if (type === 'explore') { var b = await explore(1, '都市'); if (!b || b.length < 1) return { passed: false, message: '空' }; return { passed: true, message: '发现' + b.length + '条' }; }
  if (type === 'bookInfo') { var r = await bookInfo('https://www.qishu33.com/xiaoshuo/142580/'); if (!r || !r.name) return { passed: false, message: '空' }; return { passed: true, message: r.name + ' ' + r.author }; }
  if (type === 'chapterList') { var r = await chapterList('https://www.qishu33.com/xiaoshuo/142580/'); if (!r || r.length < 1) return { passed: false, message: '空' }; return { passed: true, message: r.length + '章 ' + r[0].name + ' ~ ' + r[r.length-1].name }; }
  if (type === 'chapterContent') { var r = await chapterContent('https://www.qishu33.com/xiaoshuo/wudaochangsheng0congliehukaishishuashulianduxiuxing/read_1.html'); if (!r || r.length < 100) return { passed: false, message: '短' }; return { passed: true, message: r.length + '字 ' + r.substring(0, 30) }; }
  return { passed: false, message: '?' };
}
广告