P5韩漫

https://www.4p5mha.work

zpccool (13551) 1天前 下载:428

漫画 漫画 韩漫 日漫 免费漫画
P5韩漫(4p5mha.work),免费韩漫、日漫在线阅读平台。
二维码导入(APP尚未完成该功能)
// @name        P5韩漫
// @version     1.0.0
// @uuid        p5hanman
// @author      Ai
// @url         https://www.4p5mha.work
// @logo        https://stpic.se8manhua.club/static/images/favicon.ico
// @type        comic
// @enabled     true
// @tags        漫画,韩漫,日漫,免费漫画
// @description P5韩漫(4p5mha.work),免费韩漫、日漫在线阅读平台。

// ─── 内置测试 ─────────────────────────────────────────────────────────────

async function TEST(type) {
  if (type === '__list__') return ['search', 'explore'];

  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].name && results[i].name.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 + ' 条结果 ✓' };
  }

  return { passed: false, message: '未知测试类型: ' + type };
}

// ─── 配置 ─────────────────────────────────────────────────────────────────

var BASE = 'https://www.4p5mha.work';
var MOBILE_UA = 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36';
var HEADERS = { 'User-Agent': MOBILE_UA };

var EXPLORE_CATEGORIES = {
  '最新更新': '/update',
  '热门漫画': '/rank',
  '完结漫画': '/booklist?end=1'
};

// ─── 工具函数 ──────────────────────────────────────────────────────────────

function toAbs(href) {
  if (!href) return '';
  if (href.indexOf('http') === 0) return href;
  return BASE + (href.charAt(0) === '/' ? href : '/' + href);
}

function trim(s) {
  if (!s) return '';
  return s.replace(/^\s+|\s+$/g, '');
}

// ─── 搜索 ─────────────────────────────────────────────────────────────────

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

  var url = BASE + '/search?q=' + legado.urlEncode(keyword);
  legado.log('[search] url=' + url);

  var html = await legado.http.get(url, HEADERS);
  legado.log('[search] html长度=' + html.length);
  var doc = legado.dom.parse(html);
  var items = legado.dom.selectAll(doc, 'ul.book-list li');
  legado.log('[search] 找到 ' + items.length + ' 条结果');

  var results = [];
  for (var i = 0; i < items.length; i++) {
    var item = items[i];
    try {
      var aEl = legado.dom.select(item, 'div.book-list-cover a');
      var href = aEl ? legado.dom.attr(aEl, 'href') : '';
      var bookUrl = toAbs(href);

      var imgEl = legado.dom.select(item, 'img.book-list-cover-img');
      var cover = imgEl ? legado.dom.attr(imgEl, 'data-original') : '';
      if (!cover && imgEl) cover = legado.dom.attr(imgEl, 'src');

      var titleEl = legado.dom.select(item, 'p.book-list-info-title');
      var name = titleEl ? trim(legado.dom.text(titleEl)) : '';
      if (!name && aEl) name = trim(legado.dom.attr(aEl, 'title'));

      if (!bookUrl || !name) continue;

      results.push({
        name: name,
        bookUrl: bookUrl,
        coverUrl: cover || '',
        author: '',
        intro: '',
        kind: '漫画',
        lastChapter: ''
      });
      legado.log('[search] [' + i + '] name=' + name + ' url=' + bookUrl);
    } catch (e) {
      legado.log('[search] item ' + i + ' error: ' + e);
    }
  }

  legado.dom.free(doc);
  legado.log('[search] 返回 ' + results.length + ' 条');
  return results;
}

// ─── 书籍详情 ─────────────────────────────────────────────────────────────

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

  var html = await legado.http.get(bookUrl, HEADERS);
  legado.log('[bookInfo] html长度=' + html.length);
  var doc = legado.dom.parse(html);
  legado.log('[bookInfo] dom解析完成');

  // 书名
  var titleEl = legado.dom.select(doc, 'p.detail-main-info-title');
  var name = titleEl ? trim(legado.dom.text(titleEl)) : '';
  legado.log('[bookInfo] name=' + name);

  // 封面
  var coverEl = legado.dom.select(doc, 'div.detail-main-cover img');
  var cover = coverEl ? legado.dom.attr(coverEl, 'data-original') : '';
  if (!cover && coverEl) cover = legado.dom.attr(coverEl, 'src');
  legado.log('[bookInfo] cover=' + (cover ? cover.substring(0, 50) : ''));

  // 作者 - 简单正则从 html 中提取
  var authorMatch = html.match(/作者[::]\s*<a[^>]*>([^<]*)<\/a>/);
  var author = authorMatch ? trim(authorMatch[1]) : '';
  legado.log('[bookInfo] author=' + author);

  // 简介
  var descEl = legado.dom.select(doc, 'p.detail-desc');
  var intro = descEl ? trim(legado.dom.text(descEl)) : '';
  legado.log('[bookInfo] intro长度=' + intro.length);

  // 最新章节 - 只取最后一个 a.chapteritem
  var lastChapEl = legado.dom.select(doc, 'ul.detail-list-1 li:last-child a');
  var latestChapter = lastChapEl ? trim(legado.dom.text(lastChapEl)) : '';
  legado.log('[bookInfo] latestChapter=' + latestChapter);

  legado.dom.free(doc);

  return {
    name: name || '',
    author: author || '',
    coverUrl: cover || '',
    intro: intro || '',
    kind: '漫画',
    lastChapter: latestChapter,
    tocUrl: bookUrl
  };
}

// ─── 章节列表 ─────────────────────────────────────────────────────────────

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

  var html = await legado.http.get(tocUrl, HEADERS);
  var doc = legado.dom.parse(html);

  var chapterEls = legado.dom.selectAll(doc, 'a.chapteritem');
  legado.log('[chapterList] 找到 ' + chapterEls.length + ' 个章节');

  var seen = {};
  var chapters = [];
  for (var i = 0; i < chapterEls.length; i++) {
    var a = chapterEls[i];
    var href = legado.dom.attr(a, 'href');
    if (!href || href.indexOf('/chapter/') === -1) continue;
    var url = toAbs(href);
    if (seen[url]) continue;
    seen[url] = true;
    var title = trim(legado.dom.text(a));
    chapters.push({ name: title || ('第' + (i + 1) + '章'), url: url });
  }

  legado.dom.free(doc);
  legado.log('[chapterList] 去重后 ' + chapters.length + ' 章');
  return chapters;
}

// ─── 章节正文(漫画图片)────────────────────────────────────────────────────

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

  var html = await legado.http.get(chapterUrl, HEADERS);
  var doc = legado.dom.parse(html);

  var imgEls = legado.dom.selectAll(doc, 'img.lazy');
  legado.log('[chapterContent] img.lazy 找到 ' + imgEls.length + ' 张');

  var urls = [];
  for (var i = 0; i < imgEls.length; i++) {
    var img = imgEls[i];
    var src = legado.dom.attr(img, 'data-original');
    if (!src) src = legado.dom.attr(img, 'data-fallback');
    if (!src) src = legado.dom.attr(img, 'src');
    if (!src) continue;
    // 过滤 logo/icon/placeholder 等非漫画图片
    if (src.indexOf('static') !== -1) continue;
    if (src.indexOf('logo') !== -1) continue;
    if (src.indexOf('mrtx') !== -1) continue;
    if (src.indexOf('zhihu.com') !== -1) continue;
    if (src.indexOf('onerro') !== -1) continue;
    urls.push(src);
  }

  legado.dom.free(doc);
  legado.log('[chapterContent] 有效图片 ' + urls.length + ' 张,样本:' + (urls[0] || '无'));
  return JSON.stringify(urls);
}

// ─── 发现页 ───────────────────────────────────────────────────────────────

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

  // 未指定分类时返回分类名列表
  if (!category) {
    var cats = [];
    for (var k in EXPLORE_CATEGORIES) {
      cats.push(k);
    }
    return cats;
  }

  var path = EXPLORE_CATEGORIES[category];
  if (!path) {
    var cats2 = [];
    for (var k2 in EXPLORE_CATEGORIES) {
      cats2.push(k2);
    }
    return cats2;
  }

  var p = page || 1;
  var url = BASE + path;
  if (p > 1) url = url + (url.indexOf('?') !== -1 ? '&' : '?') + 'page=' + p;
  legado.log('[explore] url=' + url);

  var html = await legado.http.get(url, HEADERS);
  var doc = legado.dom.parse(html);
  var results = [];

  // 结构一:manga-list-2(/update、/booklist 等页面)
  var items = legado.dom.selectAll(doc, 'ul.manga-list-2 li');
  if (items && items.length > 0) {
    legado.log('[explore] manga-list-2 结构,共 ' + items.length + ' 条');
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      try {
        var aEl = legado.dom.select(item, 'div.manga-list-2-cover a');
        if (!aEl) aEl = legado.dom.select(item, 'a');
        if (!aEl) continue;
        var href = legado.dom.attr(aEl, 'href');
        if (!href || href.indexOf('/book/') === -1) continue;
        var bookUrl = toAbs(href);

        var imgEl = legado.dom.select(item, 'img.manga-list-2-cover-img');
        var cover = imgEl ? legado.dom.attr(imgEl, 'data-original') : '';
        if (!cover && imgEl) cover = legado.dom.attr(imgEl, 'src');

        var nameEl = legado.dom.select(item, 'p.manga-list-2-title a');
        var name = nameEl ? trim(legado.dom.text(nameEl)) : '';
        if (!name) name = trim(legado.dom.attr(aEl, 'title'));
        if (!name || !bookUrl) continue;

        results.push({
          name: name,
          bookUrl: bookUrl,
          coverUrl: cover || '',
          author: '',
          intro: '',
          kind: '漫画',
          lastChapter: ''
        });
      } catch (e) {
        legado.log('[explore] item ' + i + ' error: ' + e);
      }
    }
  } else {
    // 结构二:rank-list(/rank 页面,<a href> 直接包裹 <li>)
    var rankLinks = legado.dom.selectAll(doc, 'ul.rank-list a[href]');
    legado.log('[explore] rank-list 结构,共 ' + (rankLinks ? rankLinks.length : 0) + ' 条');
    if (rankLinks) {
      for (var j = 0; j < rankLinks.length; j++) {
        var a = rankLinks[j];
        try {
          var href2 = legado.dom.attr(a, 'href');
          if (!href2 || href2.indexOf('/book/') === -1) continue;
          var bookUrl2 = toAbs(href2);

          var imgEl2 = legado.dom.select(a, 'img.rank-list-cover-img');
          var cover2 = imgEl2 ? legado.dom.attr(imgEl2, 'data-original') : '';
          if (!cover2 && imgEl2) cover2 = legado.dom.attr(imgEl2, 'src');

          var nameEl2 = legado.dom.select(a, 'p.rank-list-info-right-title');
          var name2 = nameEl2 ? trim(legado.dom.text(nameEl2)) : '';
          if (!name2) name2 = trim(legado.dom.attr(a, 'title'));
          if (!name2 || !bookUrl2) continue;

          results.push({
            name: name2,
            bookUrl: bookUrl2,
            coverUrl: cover2 || '',
            author: '',
            intro: '',
            kind: '漫画',
            lastChapter: ''
          });
        } catch (e2) {
          legado.log('[explore] rank item ' + j + ' error: ' + e2);
        }
      }
    }
  }

  legado.dom.free(doc);
  legado.log('[explore] 返回 ' + results.length + ' 条');
  return results;
}
广告