fix search bug from manhuagui (#119)

* add new source from comick

* fix some code

* fix gif load and comic list info(none-type/chapter/volume)

* add some comick hidden tags

* revise coding error in file

* info updata time

* fix no-EN error

* add new function

- Multi-language comic selection support
- Added comic recommendations
- Fixed empty chapter return bug
- Resolved tag click issues
- Optimized data processing

* Optimize network request

Remove redundant requests and prevent async deadlocks

* Update comick.js

* new small comic source from baihehui

* Fixed some bugs and added some sorting methods

* Fixed some bugs and added some sorting methods

* Add a new resource from ykmh

* Remove invalid request

* fixed chapter api

* Update index.json

* Update index.json

* Update comick.js

* fix search bug from manhuagui

Fix ”querySelectorAll“ bug in search page.
Add multi-group of chapters in info page.
This commit is contained in:
Zion
2025-08-01 08:52:44 +08:00
committed by GitHub
parent 6e52854782
commit 08756ee659
2 changed files with 169 additions and 34 deletions

View File

@@ -96,7 +96,7 @@
"name": "漫画柜",
"fileName": "manhuagui.js",
"key": "manhuagui",
"version": "1.0.0"
"version": "1.0.1"
},
{
"name": "优酷漫画",

View File

@@ -8,7 +8,7 @@ class ManHuaGui extends ComicSource {
// unique id of the source
key = "ManHuaGui";
version = "1.0.0";
version = "1.0.1";
minAppVersion = "1.4.0";
@@ -17,6 +17,20 @@ class ManHuaGui extends ComicSource {
"https://cdn.jsdelivr.net/gh/venera-app/venera-configs@main/manhuagui.js";
baseUrl = "https://www.manhuagui.com";
isAppVersionAfter(target) {
if (!APP || !APP.version) return false;
let current = APP.version;
let targetArr = target.split('.');
let currentArr = current.split('.');
for (let i = 0; i < 3; i++) {
if (parseInt(currentArr[i]) < parseInt(targetArr[i])) {
return false;
}
}
return true;
}
async getHtml(url) {
let headers = {
accept:
@@ -624,6 +638,76 @@ class ManHuaGui extends ComicSource {
},
};
/**
* 专门解析搜索结果页面中的漫画信息
* @param {HTMLElement} item - 搜索结果中的单个漫画项
* @returns {Comic} - 解析后的漫画对象
*/
parseSearchComic(item) {
try {
// 获取漫画链接和ID
let linkElement = item.querySelector(".book-detail dl dt a");
if (!linkElement) return null;
let url = linkElement.attributes["href"];
let id = url.split("/")[2];
let title = linkElement.text.trim();
// 获取封面图片
let coverElement = item.querySelector(".book-cover .bcover img");
let cover = coverElement ? coverElement.attributes["src"] : null;
if (cover) {
cover = cover.startsWith("//") ? `https:${cover}` : cover;
}
// 获取更新状态和描述
let statusElement = item.querySelector(".tags.status span .red");
let status = statusElement ? statusElement.text.trim() : "";
let updateElement = item.querySelector(".tags.status span .red:nth-child(2)");
let updateTime = updateElement ? updateElement.text.trim() : "";
// 获取评分信息
let scoreElement = item.querySelector(".book-score .score-avg strong");
let score = scoreElement ? scoreElement.text.trim() : "";
// 获取作者信息
let authorElements = item.querySelectorAll(".tags a[href*='/author/']");
let author = authorElements.length > 0
? authorElements.map(a => a.text.trim()).join(", ")
: "";
// 获取类型信息
let typeElements = item.querySelectorAll(".tags a[href*='/list/']");
let types = typeElements.length > 0
? typeElements.map(a => a.text.trim())
: [];
// 获取简介
let introElement = item.querySelector(".intro span");
let description = introElement ? introElement.text.replace("简介:", "").trim() : "";
// 如果简介为空,使用更新状态作为描述
if (!description && status) {
description = `状态: ${status}`;
if (updateTime) description += `, 更新: ${updateTime}`;
}
return new Comic({
id,
title,
cover,
description,
tags: [...types, status],
author,
score
});
} catch (error) {
console.error("解析搜索结果项时出错:", error);
return null;
}
}
/// search related
search = {
/**
@@ -634,44 +718,63 @@ class ManHuaGui extends ComicSource {
* @returns {Promise<{comics: Comic[], maxPage: number}>}
*/
load: async (keyword, options, page) => {
let url = `${this.baseUrl}/s/${keyword}_p${page}.html`;
let url = ""
if (options[0]) {
let type = options[0].split("-")[0];
if (type == '0') {
url = `${this.baseUrl}/s/${keyword}_p${page}.html`;
} else{
url = `${this.baseUrl}/s/${keyword}_o${type}_p${page}.html`;
}
}else{
url = `${this.baseUrl}/s/${keyword}_p${page}.html`;
}
let document = await this.getHtml(url);
let comicNum = document
.querySelector(".result-count")
.querySelectorAll("strong")[1].text;
// 检查是否有结果计数元素
let resultCount = document.querySelector(".result-count");
if (!resultCount) {
// 没有搜索结果或页面结构不同
return {
comics: [],
maxPage: 1
};
}
let comicNum = resultCount.querySelectorAll("strong")[1].text;
comicNum = parseInt(comicNum);
// 每页10个
let maxPage = Math.ceil(comicNum / 10);
let bookshelf = document
.querySelector("#contList")
.querySelectorAll("li");
let comics = bookshelf.map((e) => this.parseComic(e));
// 在搜索结果页面中,漫画列表位于 .book-result ul 下
let comicList = document.querySelector(".book-result ul");
if (!comicList) {
return {
comics: [],
maxPage: maxPage || 1
};
}
// 使用专门的搜索解析函数解析每个漫画项
let comics = comicList.querySelectorAll("li.cf")
.map(item => this.parseSearchComic(item))
.filter(comic => comic !== null); // 过滤掉解析失败的项
return {
comics,
maxPage,
};
},
// provide options for search
optionList: [
{
// [Optional] default is `select`
// type: select, multi-select, dropdown
// For select, there is only one selected value
// For multi-select, there are multiple selected values or none. The `load` function will receive a json string which is an array of selected values
// For dropdown, there is one selected value at most. If no selected value, the `load` function will receive a null
type: "select",
// For a single option, use `-` to separate the value and text, left for value, right for text
options: ["0-time", "1-popular"],
// option label
options: ["0-最新更新", "1-最近最热","2-最新上架", "3-评分最高"],
label: "sort",
// default selected options. If not set, use the first option as default
default: null,
},
],
// enable tags suggestions
enableTagsSuggestions: false,
};
@@ -734,20 +837,52 @@ class ManHuaGui extends ComicSource {
let updateTime = detail_list[8].text.trim();
// ANCHOR 章节信息
let chapters = new Map();
let chapter_list = document.querySelector("#chapter-list-1");
if (!chapter_list) {
chapter_list = document.querySelector("#chapter-list-0");
}
let lis = chapter_list.querySelectorAll("li");
// 支持多分组
let chaptersMap = new Map();
// 查找所有章节分组标题
let chapterGroups = document.querySelectorAll(".chapter h4 span");
// 处理每个分组
for (let i = 0; i < chapterGroups.length; i++) {
let groupName = chapterGroups[i].text.trim();
let groupChapters = new Map();
// 获取对应的章节列表
let chapterList = document.querySelectorAll(".chapter-list")[i];
if (chapterList) {
let lis = chapterList.querySelectorAll("li");
for (let li of lis) {
let a = li.querySelector("a");
let i = a.attributes["href"].split("/").pop().replace(".html", "");
let id = a.attributes["href"].split("/").pop().replace(".html", "");
let title = a.querySelector("span").text.trim();
chapters.set(i, title);
groupChapters.set(id, title);
}
// chapters 升序
// 章节升序排列
groupChapters = new Map([...groupChapters].sort((a, b) => a[0] - b[0]));
// 将分组添加到总的章节映射中
chaptersMap.set(groupName, groupChapters);
}
}
// 兼容旧版本如果app版本不支持多分组则合并所有分组
let chapters;
if (this.isAppVersionAfter && this.isAppVersionAfter("1.3.0")) {
// 支持多分组
chapters = chaptersMap;
} else {
// 合并所有分组
chapters = new Map();
for (let [_, groupChapters] of chaptersMap) {
for (let [id, title] of groupChapters) {
chapters.set(id, title);
}
}
// 章节升序
chapters = new Map([...chapters].sort((a, b) => a[0] - b[0]));
}
//ANCHOR - 推荐
let recommend = [];