mirror of
https://github.com/venera-app/venera-configs.git
synced 2025-09-27 00:27:23 +00:00

* 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
388 lines
10 KiB
JavaScript
388 lines
10 KiB
JavaScript
/** @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,
|
|
};
|
|
},
|
|
};
|
|
}
|