mirror of
https://github.com/venera-app/venera-configs.git
synced 2025-09-27 00:27:23 +00:00
Manwaba (#118)
* feat: 添加漫蛙漫画源实现基础功能 * refactor(api): 重构网络请求和数据处理逻辑 - 将 `fetchJson` 拆分为 `getJson` 和 `postJson` 方法,增强类型安全 - 更新基础 URL 移除尾部斜杠 - 实现分类、搜索和详情页的实际 API 调用 - 完善漫画状态显示和分类选项 - 移除冗余的 `initFunc` 方法 * refactor: 移除未实现的收藏相关功能代码 清理未实现的收藏功能相关代码,包括添加/删除收藏、加载收藏夹等功能,以保持代码库整洁 * refactor(manwaba): 重构API响应处理逻辑并实现loadInfo方法 - 修改getJson方法直接返回完整JSON响应,不再处理特定code和data字段 - 重构分类列表和搜索结果的data字段处理逻辑 - 实现loadInfo方法获取漫画详情信息 * refactor(api): 重构API请求方法并更新基础URL - 将多个独立的请求方法合并为统一的fetchJson方法 - 更新基础URL为新的API端点 - 简化参数处理和请求逻辑 - 移除不再使用的工具方法 * fix: 将漫画ID转换为字符串类型以避免潜在的类型错误 * refactor: 将baseUrl重命名为api以提升代码可读性 统一将baseUrl变量名改为api,使其更符合实际用途,提高代码可读性和一致性 * refactor(ManWaBa): 优化fetchJson默认参数并添加日志功能 - 为fetchJson方法的payload参数添加默认值undefined - 新增logger对象提供error/info/warn日志方法 - 在loadInfo方法中添加日志记录 - 移除未使用的可选方法以简化代码结构 * fix: 修复fetchJson调用时payload参数未定义的问题 确保在调用fetchJson时明确传递payload为undefined,避免潜在的类型错误 * refactor(ManWaBa): 优化漫画信息加载和章节图片获取逻辑 重构漫画信息加载和章节图片获取的代码,提取重复参数为变量,简化请求逻辑 移除未使用的onImageLoad和onThumbnailLoad方法,集中处理图片获取功能 * feat: 添加漫蛙吧源到index.json
This commit is contained in:
@@ -103,5 +103,10 @@
|
||||
"fileName": "ykmh.js",
|
||||
"key": "ykmh",
|
||||
"version": "1.0.0"
|
||||
},{
|
||||
"name": "漫蛙吧",
|
||||
"fileName": "manwaba.js",
|
||||
"key": "manwaba",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
|
387
manwaba.js
Normal file
387
manwaba.js
Normal file
@@ -0,0 +1,387 @@
|
||||
/** @type {import('./_venera_.js')} */
|
||||
class ManWaBa extends ComicSource {
|
||||
// Note: The fields which are marked as [Optional] should be removed if not used
|
||||
|
||||
// name of the source
|
||||
name = "漫蛙吧";
|
||||
|
||||
// unique id of the source
|
||||
key = "manwaba";
|
||||
|
||||
version = "1.0.0";
|
||||
|
||||
minAppVersion = "1.4.0";
|
||||
|
||||
// update url
|
||||
url = "https://cdn.jsdelivr.net/gh/venera-app/venera-configs@main/manwaba.js";
|
||||
|
||||
api = "https://www.manwaba.com/api/v1";
|
||||
|
||||
init() {
|
||||
/**
|
||||
* Sends an HTTP request.
|
||||
* @param {string} url - The URL to send the request to.
|
||||
* @param {string} method - The HTTP method (e.g., GET, POST, PUT, PATCH, DELETE).
|
||||
* @param {Object} params - The query parameters to include in the request.
|
||||
* @param {Object} headers - The headers to include in the request.
|
||||
* @param {string} payload - The payload to include in the request.
|
||||
* @returns {Promise<Object>} The response from the request.
|
||||
*/
|
||||
this.fetchJson = async (
|
||||
url,
|
||||
{ method = "GET", params, headers, payload }
|
||||
) => {
|
||||
if (params) {
|
||||
let params_str = Object.keys(params)
|
||||
.map((key) => `${key}=${params[key]}`)
|
||||
.join("&");
|
||||
url += `?${params_str}`;
|
||||
}
|
||||
let res = await Network.sendRequest(method, url, headers, payload);
|
||||
if (res.status !== 200) {
|
||||
throw `Invalid status code: ${res.status}, body: ${res.body}`;
|
||||
}
|
||||
let json = JSON.parse(res.body);
|
||||
return json;
|
||||
};
|
||||
this.logger = {
|
||||
error: (msg) => {
|
||||
log("error", this.name, msg);
|
||||
},
|
||||
info: (msg) => {
|
||||
log("info", this.name, msg);
|
||||
},
|
||||
warn: (msg) => {
|
||||
log("warning", this.name, msg);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// explore page list
|
||||
explore = [
|
||||
{
|
||||
// title of the page.
|
||||
// title is used to identify the page, it should be unique
|
||||
title: this.name,
|
||||
|
||||
/// multiPartPage or multiPageComicList or mixed
|
||||
type: "singlePageWithMultiPart",
|
||||
|
||||
/**
|
||||
* load function
|
||||
* @param page {number | null} - page number, null for `singlePageWithMultiPart` type
|
||||
* @returns {{}}
|
||||
* - for `multiPartPage` type, return [{title: string, comics: Comic[], viewMore: PageJumpTarget}]
|
||||
* - for `multiPageComicList` type, for each page(1-based), return {comics: Comic[], maxPage: number}
|
||||
* - for `mixed` type, use param `page` as index. for each index(0-based), return {data: [], maxPage: number?}, data is an array contains Comic[] or {title: string, comics: Comic[], viewMore: string?}
|
||||
*/
|
||||
load: async (page) => {
|
||||
let params = {
|
||||
page: 1,
|
||||
pageSize: 6,
|
||||
type: "",
|
||||
flag: false,
|
||||
};
|
||||
const url = `${this.api}/json/home`;
|
||||
const data = await this.fetchJson(url, { params }).then(
|
||||
(res) => res.data
|
||||
);
|
||||
let magnaList = {
|
||||
热门: data.comicList,
|
||||
古风: data.gufengList,
|
||||
玄幻: data.xuanhuanList,
|
||||
校园: data.xiaoyuanList,
|
||||
};
|
||||
function parseComic(comic) {
|
||||
return new Comic({
|
||||
id: comic.id.toString(),
|
||||
title: comic.title,
|
||||
subTitle: comic.author,
|
||||
cover: comic.pic,
|
||||
tags: comic.tags.split(","),
|
||||
});
|
||||
}
|
||||
let result = {};
|
||||
for (let key in magnaList) {
|
||||
result[key] = magnaList[key].map(parseComic);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// categories
|
||||
category = {
|
||||
/// title of the category page, used to identify the page, it should be unique
|
||||
title: this.name,
|
||||
parts: [
|
||||
{
|
||||
// title of the part
|
||||
name: "类型",
|
||||
|
||||
// fixed or random or dynamic
|
||||
// if random, need to provide `randomNumber` field, which indicates the number of comics to display at the same time
|
||||
// if dynamic, need to provide `loader` field, which indicates the function to load comics
|
||||
type: "fixed",
|
||||
|
||||
// Remove this if type is dynamic
|
||||
categories: [
|
||||
"全部",
|
||||
"热血",
|
||||
"玄幻",
|
||||
"恋爱",
|
||||
"冒险",
|
||||
"古风",
|
||||
"都市",
|
||||
"穿越",
|
||||
"奇幻",
|
||||
"其他",
|
||||
"搞笑",
|
||||
"少男",
|
||||
"战斗",
|
||||
"重生",
|
||||
"逆袭",
|
||||
"爆笑",
|
||||
"少年",
|
||||
"后宫",
|
||||
"系统",
|
||||
"BL",
|
||||
"韩漫",
|
||||
"完整版",
|
||||
"19r",
|
||||
"台版",
|
||||
],
|
||||
|
||||
itemType: "category",
|
||||
categoryParams: [
|
||||
"",
|
||||
"热血",
|
||||
"玄幻",
|
||||
"恋爱",
|
||||
"冒险",
|
||||
"古风",
|
||||
"都市",
|
||||
"穿越",
|
||||
"奇幻",
|
||||
"其他",
|
||||
"搞笑",
|
||||
"少男",
|
||||
"战斗",
|
||||
"重生",
|
||||
"逆袭",
|
||||
"爆笑",
|
||||
"少年",
|
||||
"后宫",
|
||||
"系统",
|
||||
"BL",
|
||||
"韩漫",
|
||||
"完整版",
|
||||
"19r",
|
||||
"台版",
|
||||
],
|
||||
},
|
||||
],
|
||||
// enable ranking page
|
||||
enableRankingPage: false,
|
||||
};
|
||||
|
||||
/// category comic loading related
|
||||
categoryComics = {
|
||||
/**
|
||||
* load comics of a category
|
||||
* @param category {string} - category name
|
||||
* @param param {string?} - category param
|
||||
* @param options {string[]} - options from optionList
|
||||
* @param page {number} - page number
|
||||
* @returns {Promise<{comics: Comic[], maxPage: number}>}
|
||||
*/
|
||||
load: async (category, param, options, page) => {
|
||||
let url = `${this.api}/json/cate`;
|
||||
let payload = JSON.stringify({
|
||||
page: {
|
||||
page: page,
|
||||
pageSize: 10,
|
||||
},
|
||||
category: "comic",
|
||||
sort: parseInt(options[2]),
|
||||
comic: {
|
||||
status: parseInt(options[0] == "2" ? -1 : options[0]),
|
||||
day: parseInt(options[1]),
|
||||
tag: param,
|
||||
},
|
||||
video: {
|
||||
year: 0,
|
||||
typeId: 0,
|
||||
typeId1: 0,
|
||||
area: "",
|
||||
lang: "",
|
||||
status: -1,
|
||||
day: 0,
|
||||
},
|
||||
novel: {
|
||||
status: -1,
|
||||
day: 0,
|
||||
sortId: 0,
|
||||
},
|
||||
});
|
||||
|
||||
let data = await this.fetchJson(url, {
|
||||
method: "POST",
|
||||
payload,
|
||||
}).then((res) => res.data);
|
||||
|
||||
function parseComic(comic) {
|
||||
return new Comic({
|
||||
id: comic.url.split("/").pop(),
|
||||
title: comic.title,
|
||||
subTitle: comic.author,
|
||||
cover: comic.pic,
|
||||
tags: comic.tags.split(","),
|
||||
description: comic.intro,
|
||||
status: comic.status == 0 ? "连载中" : "已完结",
|
||||
});
|
||||
}
|
||||
return {
|
||||
comics: data.map(parseComic),
|
||||
maxPage: 100,
|
||||
};
|
||||
},
|
||||
// provide options for category comic loading
|
||||
optionList: [
|
||||
{
|
||||
options: ["2-全部", "0-连载中", "1-已完结"],
|
||||
},
|
||||
{
|
||||
options: [
|
||||
"0-全部",
|
||||
"1-周一",
|
||||
"2-周二",
|
||||
"3-周三",
|
||||
"4-周四",
|
||||
"5-周五",
|
||||
"6-周六",
|
||||
"7-周日",
|
||||
],
|
||||
},
|
||||
{
|
||||
options: ["0-更新", "1-新作", "2-畅销", "3-热门", "4-收藏"],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/// search related
|
||||
search = {
|
||||
/**
|
||||
* load search result
|
||||
* @param keyword {string}
|
||||
* @param options {string[]} - options from optionList
|
||||
* @param page {number}
|
||||
* @returns {Promise<{comics: Comic[], maxPage: number}>}
|
||||
*/
|
||||
load: async (keyword, options, page) => {
|
||||
const pageSize = 20;
|
||||
let url = `${this.api}/json/search`;
|
||||
let params = {
|
||||
keyword,
|
||||
type: "mh",
|
||||
page,
|
||||
pageSize,
|
||||
};
|
||||
let data = await this.fetchJson(url, { params }).then((res) => res.data);
|
||||
let total = data.total;
|
||||
let comics = data.list.map((item) => {
|
||||
return new Comic({
|
||||
id: item.id.toString(),
|
||||
title: item.title,
|
||||
subTitle: item.author,
|
||||
cover: item.cover,
|
||||
tags: item.tags.split(","),
|
||||
description: item.description,
|
||||
status: item.status == 0 ? "连载中" : "已完结",
|
||||
});
|
||||
});
|
||||
let maxPage = Math.ceil(total / pageSize);
|
||||
return {
|
||||
comics,
|
||||
maxPage,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/// single comic related
|
||||
comic = {
|
||||
/**
|
||||
* load comic info
|
||||
* @param id {string}
|
||||
* @returns {Promise<ComicDetails>}s
|
||||
*/
|
||||
loadInfo: async (id) => {
|
||||
let url = `${this.api}/json/comic/${id}`;
|
||||
let data = await this.fetchJson(url, { payload: undefined }).then(
|
||||
(res) => res.data
|
||||
);
|
||||
this.logger.warn(`loadInfo: ${data}`);
|
||||
let chapterId = data.id;
|
||||
let chapterApi = `${this.api}/json/comic/chapter`;
|
||||
let params = {
|
||||
comicId: chapterId,
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
};
|
||||
let pageRes = await this.fetchJson(chapterApi, { params });
|
||||
let total = pageRes.pagination.total;
|
||||
|
||||
let chapterRes = await this.fetchJson(chapterApi, {
|
||||
params: {
|
||||
...params,
|
||||
pageSize: total,
|
||||
},
|
||||
});
|
||||
let chapterList = chapterRes.data;
|
||||
let chapters = new Map();
|
||||
chapterList.forEach((item) => {
|
||||
chapters.set(item.id.toString(), item.title.toString());
|
||||
});
|
||||
|
||||
return new ComicDetails({
|
||||
title: data.title.toString(),
|
||||
subTitle: data.author.toString(),
|
||||
cover: data.cover,
|
||||
tags: {
|
||||
类型: data.tags.split(","),
|
||||
状态: data.status == 0 ? "连载中" : "已完结",
|
||||
},
|
||||
chapters,
|
||||
description: data.intro,
|
||||
updateTime: new Date(data.editTime * 1000).toLocaleDateString(),
|
||||
});
|
||||
},
|
||||
/**
|
||||
* load images of a chapter
|
||||
* @param comicId {string}
|
||||
* @param epId {string?}
|
||||
* @returns {Promise<{images: string[]}>}
|
||||
*/
|
||||
loadEp: async (comicId, epId) => {
|
||||
let imgApi = `${this.api}/comic/image/${epId}`;
|
||||
let params = {
|
||||
page: 1,
|
||||
pageSize: 1,
|
||||
imageSource: "https://tu.mhttu.cc",
|
||||
};
|
||||
let pageNum = await this.fetchJson(imgApi, {
|
||||
params,
|
||||
}).then((res) => res.data.pagination.total);
|
||||
let imageRes = await this.fetchJson(imgApi, {
|
||||
params: {
|
||||
...params,
|
||||
pageSize: pageNum,
|
||||
},
|
||||
}).then((res) => res.data.images);
|
||||
let images = imageRes.map((item) => item.url);
|
||||
return {
|
||||
images,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user