uaa.

https://www.uaa.com/

zpccool (13551) 1天前 下载:504

小说
完整书源:支持热门小说、热辣视频、热门禁漫及所有排行榜,使用浏览器探测绕过 Cloudflare Shield
二维码导入(APP尚未完成该功能)
// @name        uaa.
// @uuid        uaa.
// @version     0.4.0
// @author      Ai
// @url         https://www.uaa.com/
// @type        novel
// @enabled     true
// @description 完整书源:支持热门小说、热辣视频、热门禁漫及所有排行榜,使用浏览器探测绕过 Cloudflare Shield

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

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// init:初始化时创建浏览器会话
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

function init() {
  legado.log('[init] 初始化浏览器会话...');
  legado.log('[init] 浏览器会话初始化完成');
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 探测辅助函数:通过浏览器获取页面内容
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

async function _fetchPageViaProxy(url, jscode) {
  legado.log('[_fetchPageViaProxy] url=' + url);
  try {
    var result = await legado.browser.run(url, jscode || 'return document.documentElement.innerHTML;', {
      visible: true,
      waitUntil: 'load',
      timeoutSecs: 60
    });
    return result;
  } catch (e) {
    legado.log('[_fetchPageViaProxy] 错误: ' + e.message);
    throw e;
  }
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 发现页:GETALL 返回所有分类
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

  if (category === 'GETALL') {
    // 返回我们定义的标准分类,而不是动态提取的全部分类
    return [
      '热门小说', '热辣视频', '热门禁漫',
      '新增小说', '完结小说', '最新小说', '连载小说', '推荐小说'
    ];
  }

  // 获取指定分类的内容列表
  try {
    // 构建分类 URL 映射
    var categoryMap = {
      // 小说分类
      '热门小说': '/novel',
      '新增小说': '/novel?sort=new',
      '完结小说': '/novel?status=finish',
      '最新小说': '/novel?sort=latest',
      '连载小说': '/novel?status=serial',
      '推荐小说': '/novel?sort=recommend',

      // 视频分类
      '热辣视频': '/video',
      '视频推荐': '/video?sort=recommend',
      '视频热门': '/video?sort=hot',

      // 漫画分类
      '热门禁漫': '/comic',
      '漫画推荐': '/comic?sort=recommend',
      '漫画热门': '/comic?sort=hot',

      // 有声分类
      '有声推荐': '/audio?sort=recommend',
      '有声热门': '/audio?sort=hot'
    };

    var categoryUrl = categoryMap[category];

    // 如果分类未定义,尝试通用格式
    if (!categoryUrl) {
      if (category.includes('视频') || category.includes('video')) {
        categoryUrl = '/video';
      } else if (category.includes('漫画') || category.includes('comic')) {
        categoryUrl = '/comic';
      } else if (category.includes('有声') || category.includes('audio')) {
        categoryUrl = '/audio';
      } else {
        categoryUrl = '/novel';
      }
    }

    // 添加分页参数
    if (page && page > 1) {
      categoryUrl += (categoryUrl.indexOf('?') > -1 ? '&' : '?') + 'page=' + page;
    }

    var fullUrl = BASE + categoryUrl;
    legado.log('[explore] 加载分类 "' + category + '" 第 ' + page + ' 页 (url=' + fullUrl + ')');

    // 为视频页面使用较短的等待时间,避免超时
    var waitTime = (categoryUrl.includes('/video') ? 5000 : 20000);

    var bookResult = await _fetchPageViaProxy(fullUrl, `
      await new Promise(r => setTimeout(r, ${waitTime}));

      // 第一阶段:直接寻找内容链接(最快)
      var items = [];

      // 优先使用内容链接
      items = Array.from(document.querySelectorAll('a[href*="/intro"], a[href*="/video/intro"], a[href*="/comic/"]'));

      // 如果没有找到足够的内容,降级到容器搜索(只搜一个主容器)
      if (items.length < 10) {
        var mainContainer = document.querySelector('main, [role="main"], [class*="content"]');
        if (mainContainer) {
          items = Array.from(mainContainer.querySelectorAll('a[href*="/"]')).filter(function(a) {
            return a.href.length > 20 && (a.href.includes('/novel') || a.href.includes('/video') || a.href.includes('/comic'));
          });
        }
      }

      var debugInfo = {
        itemsFound: items.length,
        pageTitle: document.title,
        readyState: document.readyState,
        bodyLength: document.body.innerText.length,
        htmlSnippet: document.documentElement.innerHTML.substring(0, 300)
      };

      var books = items.slice(0, 100).map(function(el) {
        var linkEl = null;

        // 优先使用链接元素本身
        if (el.tagName === 'A' && el.href) {
          linkEl = el;
        }

        // 否则在元素内查找链接
        if (!linkEl) {
          linkEl = el.querySelector('a');
        }

        // 获取标题 - 使用轻量级属性而非 innerText
        var name = '';
        var titleEl = el.querySelector('h3, h4, .title, [class*="name"], .book-name, .video-name');

        if (titleEl) {
          // 避免计算 innerText,使用 textContent 或 title 属性
          name = (titleEl.textContent || titleEl.title || '').trim();
        }

        // 如果还是没有标题,尝试从链接元素的 title 或 alt 获取
        if (!name && linkEl) {
          name = (linkEl.title || linkEl.alt || linkEl.textContent || '').trim();
        }

        // 如果都没有,从元素的属性获取
        if (!name) {
          name = (el.getAttribute('title') || el.getAttribute('alt') || '').trim();
        }

        // 清理名称中的多余文字
        if (name.length > 100) {
          name = name.substring(0, 100);
        }

        var authorEl = el.querySelector('[class*="author"], [class*="writer"], .author, [class*="director"]');
        var coverEl = el.querySelector('img');

        return {
          name: name || '未知',
          author: (authorEl ? (authorEl.textContent || '').trim() : ''),
          bookUrl: linkEl && linkEl.href ? linkEl.href : '',
          coverUrl: coverEl && coverEl.src ? coverEl.src : (coverEl && coverEl.getAttribute('src') ? coverEl.getAttribute('src') : ''),
          kind: '${category}'
        };
      }).filter(function(b) {
        // 快速过滤:先检查 URL 有效性(避免多次字符串操作)
        if (!b.bookUrl || b.bookUrl.length < 15) return false;

        // 检查是否包含导航链接
        if (b.bookUrl.includes('/list') || b.bookUrl.includes('/rank') ||
            b.bookUrl.includes('/ai/') || b.name === '未知' || b.name.length < 2) {
          return false;
        }

        // 对于每个类别,快速检查 URL 类型
        var isSafeUrl = false;
        if ('${category}'.includes('视频')) {
          isSafeUrl = b.bookUrl.includes('/video/intro') || b.bookUrl.includes('/video/') && !b.bookUrl.includes('video/list');
        } else if ('${category}'.includes('漫画')) {
          isSafeUrl = b.bookUrl.includes('/comic/');
        } else {
          isSafeUrl = b.bookUrl.includes('/intro') || b.bookUrl.includes('/novel/');
        }

        return isSafeUrl;
      });

      return {
        books: books.slice(0, 50),
        debug: debugInfo
      };
    `);

    var books = Array.isArray(bookResult) ? bookResult : (bookResult && bookResult.books ? bookResult.books : []);
    if (bookResult && bookResult.debug) {
      legado.log('[explore] DEBUG: ' + JSON.stringify(bookResult.debug));
    }
    legado.log('[explore] 分类 "' + category + '" 页 ' + page + ' 获得 ' + books.length + ' 个内容');
    return books || [];
  } catch (e) {
    legado.log('[explore] 获取分类 "' + category + '" 失败: ' + e.message);
    return [];
  }
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 书籍/内容详情:必须返回 tocUrl
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

async function bookInfo(bookUrl) {
  legado.log('[bookInfo] url=' + bookUrl);

  if (!bookUrl) {
    return { name: '', author: '', tocUrl: '', coverUrl: '' };
  }

  try {
    var infoResult = await _fetchPageViaProxy(bookUrl, `
      await new Promise(r => setTimeout(r, 3000));

      var nameEl = document.querySelector('h1, h2[class*="title"], [class*="novel-name"]');
      var authorEl = document.querySelector('[class*="author"], [class*="writer"]');
      var introEl = document.querySelector('[class*="intro"], [class*="description"]');
      var coverEl = document.querySelector('img[class*="cover"], img[alt*="cover"]');

      // 使用轻量级属性访问,避免 innerText
      var name = '';
      if (nameEl) {
        name = (nameEl.textContent || nameEl.title || '').trim();
      }
      if (!name) {
        name = document.title.split('|')[0] || '';
      }

      var author = authorEl ? (authorEl.textContent || '').trim() : '';

      var intro = '';
      if (introEl) {
        intro = (introEl.textContent || '').trim().substring(0, 500);
      }

      var coverUrl = coverEl && coverEl.src ? coverEl.src : '';

      var tocLink = document.querySelector('a[href*="/chapter"], a[href*="/list"], button[class*="chapter"]');
      var tocUrl = tocLink ? tocLink.href : bookUrl;

      if (tocUrl && !tocUrl.startsWith('http')) {
        tocUrl = window.location.origin + tocUrl;
      }

      return {
        name: name,
        author: author,
        intro: intro,
        coverUrl: coverUrl,
        tocUrl: tocUrl || bookUrl
      };
    `);

    legado.log('[bookInfo] 获取成功: ' + (infoResult ? infoResult.name : ''));
    return infoResult || { name: '', author: '', tocUrl: bookUrl, coverUrl: '' };
  } catch (e) {
    legado.log('[bookInfo] 获取失败: ' + e.message);
    return { name: '', author: '', tocUrl: bookUrl, coverUrl: '' };
  }
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 章节列表
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

async function chapterList(tocUrl) {
  legado.log('[chapterList] url=' + tocUrl);

  try {
    var chaptersResult = await _fetchPageViaProxy(tocUrl, `
      await new Promise(r => setTimeout(r, 3000));

      var links = Array.from(document.querySelectorAll('a[href*="chapter"], a[href*="read"], a[href*="intro"], li a, [class*="chapter"] a')).slice(0, 600);
      return links
        .filter(function(el) { return el.href && el.href.length > 10; })
        .map(function(el) {
          // 使用轻量级属性,避免 innerText
          var text = (el.textContent || el.title || el.alt || '').trim();
          return {
            name: text.substring(0, 100) || '未命名',
            url: el.href
          };
        })
        .slice(0, 500);
    `);

    legado.log('[chapterList] 获得 ' + (chaptersResult ? chaptersResult.length : 0) + ' 章');
    return chaptersResult || [];
  } catch (e) {
    legado.log('[chapterList] 失败: ' + e.message);
    return [];
  }
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 章节正文
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

  try {
    var contentResult = await _fetchPageViaProxy(chapterUrl, `
      await new Promise(r => setTimeout(r, 3000));

      // 优先从最具体的容器获取内容
      var contentEl = document.querySelector('[class*="content"], [class*="text"], [class*="article"], main, article, .chapter-content, .post-content');

      // 仅当确实需要 innerText 时才调用一次
      var text = '';
      if (contentEl && contentEl.textContent) {
        text = contentEl.textContent;
      } else if (document.body && document.body.textContent) {
        // 降级:只在必要时获取整个页面文本
        text = document.body.textContent;
      }

      // 快速清理文本(避免过度处理)
      var cleanedText = text
        .split('\\n')
        .slice(0, 5000)  // 限制行数避免过大
        .map(function(line) { return line.trim(); })
        .filter(function(line) {
          return line.length > 0 && line.length < 500 &&
                 !line.includes('广告') && !line.includes('脚本') &&
                 !line.includes('推广') && !line.includes('赞助');
        })
        .join('\\n');

      return cleanedText;
    `);

    legado.log('[chapterContent] 获得内容长度 ' + (contentResult ? contentResult.length : 0) + ' 字');
    return contentResult || '';
  } catch (e) {
    legado.log('[chapterContent] 获取失败: ' + e.message);
    return '';
  }
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 搜索
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

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

  try {
    var searchUrl = BASE + '/search?keyword=' + encodeURIComponent(keyword);
    if (page && page > 1) {
      searchUrl += '&page=' + page;
    }

    var searchResult = await _fetchPageViaProxy(searchUrl, `
      await new Promise(r => setTimeout(r, 5000));

      var items = Array.from(document.querySelectorAll('a[href*="/intro"], a[href*="/novel/"], a[href*="/video/"], a[href*="/comic/"]')).slice(0, 100);

      if (items.length < 5) {
        var container = document.querySelector('[class*="list"], [class*="content"], main, article');
        if (container) {
          items = Array.from(container.querySelectorAll('a')).filter(function(a) {
            return a.href.length > 10 && (a.href.includes('/intro') || a.href.includes('/novel') || a.href.includes('/video') || a.href.includes('/comic'));
          });
        }
      }

      var books = items.map(function(el) {
        var linkEl = el.tagName === 'A' ? el : el.querySelector('a');

        // 使用轻量级属性获取标题
        var name = (el.textContent || el.title || el.alt || '').trim();
        if (name.length > 100) name = name.substring(0, 100);

        var authorEl = el.querySelector('[class*="author"], span[class*="writer"]');
        var author = authorEl ? (authorEl.textContent || '').trim() : '';

        return {
          name: name || '未知',
          author: author,
          bookUrl: linkEl ? linkEl.href : '',
          coverUrl: ''
        };
      }).filter(function(b) {
        return b.name !== '未知' && b.bookUrl && b.bookUrl.length > 10;
      });

      return books.slice(0, 50);
    `);

    legado.log('[search] 搜索 "' + keyword + '" 第 ' + page + ' 页获得 ' + (searchResult ? searchResult.length : 0) + ' 个结果');
    return searchResult || [];
  } catch (e) {
    legado.log('[search] 搜索失败: ' + e.message);
    return [];
  }
}
广告