/** @type {import('./_venera_.js')} */ class YKMHSource extends ComicSource { name = "优酷漫画" key = "ykmh" version = "1.0.0" minAppVersion = "1.4.0" url = "https://cdn.jsdelivr.net/gh/venera-app/venera-configs@main/ykmh.js" get baseUrl() { return "https://www.ykmh.net"; } explore = [ { title: "优酷漫画", type: "multiPartPage", load: async (page) => { let res = await Network.get("https://www.ykmh.net") if (res.status !== 200) { throw `Invalid status code: ${res.status}` } function parseHotCarousel(html) { let hotComics = [] let carouselPattern = /
([^<]*)<\/p><\/span><\/a>
([^<]+)<\/a><\/p>/g
let match
while ((match = comicPattern.exec(html)) !== null) {
let cover = match[4]
if (!cover.startsWith('http')) {
cover = 'https://www.ykmh.net' + (cover.startsWith('/') ? cover : '/' + cover)
}
latestComics.push(new Comic({
id: match[2],
title: match[3],
cover: cover,
tags: [match[5]],
description: `更新至:${match[5]}`
}))
}
return latestComics.slice(0, 15)
}
let hotComics = parseHotCarousel(res.body)
let latestComics = parseLatestComics(res.body)
return [
{
title: "热门推荐",
comics: hotComics
},
{
title: "最新更新",
comics: latestComics
}
]
}
}
]
static category_param_dict = {
"全部": "",
"爱情": "aiqing",
"剧情": "juqing",
"欢乐向": "huanlexiang",
"格斗": "gedou",
"科幻": "kehuan",
"伪娘": "weiniang",
"节操": "jiecao",
"恐怖": "kongbu",
"悬疑": "xuanyi",
"冒险": "maoxian",
"校园": "xiaoyuan",
"治愈": "zhiyu",
"恋爱": "lianai",
"奇幻": "qihuan",
"热血": "rexue",
"限制级": "xianzhiji",
"魔法": "mofa",
"后宫": "hougong",
"魔幻": "mohuan",
"轻小说": "qingxiaoshuo",
"震撼": "zhenhan",
"纯爱": "chunai",
"少女": "shaonv",
"战争": "zhanzheng",
"武侠": "wuxia",
"搞笑": "gaoxiao",
"神鬼": "shengui",
"竞技": "jingji",
"幻想": "huanxiang",
"神魔": "shenmo",
"灵异": "lingyi",
"百合": "baihe",
"运动": "yundong",
"体育": "tiyu",
"惊悚": "jingsong",
"日常": "richang",
"绅士": "shenshi",
"颜艺": "yanyi",
"生活": "shenghuo",
"四格": "sige",
"萌系": "mengxi",
"都市": "dushi",
"同人": "tongren",
"推理": "tuili",
"耽美": "danmei",
"卖肉": "mairou",
"职场": "zhichang",
"侦探": "zhentan",
"战斗": "zhandou",
"爆笑": "baoxiao",
"总裁": "zongcai",
"美食": "meishi",
"性转换": "xingzhuanhuan",
"励志": "lizhi",
"西方魔幻": "xifangmohuan",
"改编": "gaibian",
"其他": "qita",
"宅系": "zhaixi",
"机战": "jizhan",
"乙女": "yinv",
"秀吉": "xiuji",
"舰娘": "jianniang",
"历史": "lishi",
"猎奇": "lieqi",
"社会": "shehui",
"青春": "qingchun",
"高清单行": "gaoqingdanxing",
"东方": "dongfang",
"橘味": "juwei",
"音乐舞蹈": "yinyuewudao",
"家庭": "jiating",
"ゆり": "unknown",
"彩虹": "caihong",
"少年": "shaonian",
"泡泡": "paopao",
"宫斗": "gongdou",
"动作": "dongzuo",
"青年": "qingnian",
"虐心": "nuexin",
"泛爱": "fanai",
"机甲": "jijia",
"装逼": "zhuangbi",
"#愛情": "aiqing2",
"#長條": "zhangtiao",
"#穿越": "chuanyue",
"#生活": "shenghuo2",
"TS": "TS",
"#耽美": "danmei2",
"#后宫": "hougong2",
"#节操": "jiecao2",
"#轻小说": "qingxiaoshuo2",
"#奇幻": "qihuan2",
"#悬疑": "xuanyi2",
"#校园": "xiaoyuan2",
"#爱情": "aiqing3",
"#百合": "baihe2",
"#长条": "changtiao",
"#冒险": "maoxian2",
"#搞笑": "gaoxiao2",
"#欢乐向": "huanlexiang2",
"#职场": "zhichang2",
"#神鬼": "shengui2",
"#生存": "shengcun",
"#治愈": "zhiyu2",
"#竞技": "jingji2",
"#美食": "meishi2",
"#其他": "qita2",
"#机战": "jizhan2",
"#战争": "zhanzheng2",
"#科幻": "kehuan2",
"#四格": "sige2",
"#武侠": "wuxia2",
"#重生": "zhongsheng",
"#性转换": "xingzhuanhuan2",
"#热血": "rexue2",
"#伪娘": "weiniang2",
"#异世界": "yishijie",
"#萌系": "mengxi2",
"#格斗": "gedou2",
"#励志": "lizhi2",
"#都市": "dushi2",
"#惊悚": "jingsong2",
"#侦探": "zhentan2",
"#舰娘": "jianniang2",
"#音乐舞蹈": "yinyuewudao2",
"#TL": "TL",
"#AA": "AA",
"#转生": "zhuansheng",
"#魔幻": "mohuan2",
"---": "unknown2",
"#彩色": "caise",
"福瑞": "furui",
"#FATE": "FATE",
"西幻": "xihuan",
"#C99": "C99",
"#C101": "C101",
"#历史": "lishi2",
"#C102": "C102",
"#无修正": "wuxiuzheng",
"#C103": "C103",
"#东方": "dongfang2",
"栏目": "lanmu",
"异世界": "yishijie2",
"恶搞": "egao",
"霸总": "bazong",
"古风": "gufeng",
"穿越": "chuanyue2",
"玄幻": "xuanhuan",
"日更": "rigeng",
"吸血": "xixie",
"萝莉": "luoli",
"漫改": "mangai",
"唯美": "weimei",
"宅男腐女": "zhainanfunv",
"老师": "laoshi",
"诱惑": "youhuo",
"杂志": "zazhi",
"脑洞": "naodong",
"其它": "qita3",
"#恐怖": "kongbu2",
"#C105": "C105",
"权谋": "quanmou",
"大陆": "dalu",
"日本": "riben",
"香港": "hongkong",
"台湾": "taiwan",
"欧美": "oumei",
"韩国": "hanguo",
"其它": "qita",
"儿童漫画": "ertong",
"少年漫画": "shaonian",
"少女漫画": "shaonv",
"青年漫画": "qingnian",
"已完结": "wanjie",
"连载中": "lianzai"
}
static comic_status = {
"连载中": "ongoing",
"已完结": "completed",
"暂停": "paused",
"完结": "completed",
"连载": "ongoing",
"休刊": "paused",
"未知状态": "unknown"
}
category = {
title: "优酷漫画",
parts: [
{
name: "主题",
type: "fixed",
categories: Object.keys(YKMHSource.category_param_dict),
itemType: "category",
categoryParams: Object.values(YKMHSource.category_param_dict),
}
],
enableRankingPage: false,
}
categoryComics = {
load: async (category, param, options, page) => {
let sort = "";
temp = options[1].split("-")[0]
if(temp==0){sort=""}else{sort="-"}
sort = sort + options[0].split("-")[0]
let url;
if (param === "" || param === undefined) {
url = `https://www.ykmh.net/list/${sort}/?page=${page}`;
} else {
url = `https://www.ykmh.net/list/${param}/${sort}/${page}/`;
}
let res = await Network.get(url);
if (res.status !== 200) {
throw `Invalid status code: ${res.status}`;
}
function parseComicsList(html) {
let comics = []
let comicPattern = / ]*>([^<]+)<\/a><\/p>\s* ([^<]*)<\/a><\/p>\s* ([^<]*)<\/p>/g
let match
while ((match = comicPattern.exec(html)) !== null) {
let cover = match[4]
if (!cover.startsWith('http')) {
cover = 'https://www.ykmh.net' + (cover.startsWith('/') ? cover : '/' + cover)
}
comics.push(new Comic({
id: match[2],
title: match[3],
cover: cover,
tags: [match[6] || "未知作者", match[7] || ""],
description: `作者:${match[6] || "未知作者"} | 更新至:${match[7] || "未知"}`
}))
}
return comics
}
let comics = parseSearchResults(res.body)
let maxPage = 1
let pagePattern = / [\s\S]*?<\/p>/g);
if (txtItems) {
console.log("找到txtItme元素数量:", txtItems.length);
for (let item of txtItems) {
if (item.includes('icon icon02')) {
let tagMatches = item.matchAll(/([^<]+)<\/a>/g);
if (tagMatches) {
for (let tagMatch of tagMatches) {
if (tagMatch && tagMatch[1]) {
let tagText = tagMatch[1].trim();
if (tagText && !tags.includes(tagText)) {
tags.push(tagText);
if (tagText === '连载中' || tagText === '已完结' || tagText === '完结' ||
tagText === '连载' || tagText === '暂停' || tagText === '休刊') {
status = tagText;
console.log("找到状态标签:", tagText);
}
}
}
}
}
}
}
}
console.log("解析到状态:", status, "标签:", tags);
} catch (e) {
console.warn("解析标签失败:", e);
tags = [];
}
let description = "暂无描述";
try {
let descMatch = html.match(/]*><\/a>\s*]*>\s*
([^<]+)<\/a><\/h3>/g
let match
while ((match = comicPattern.exec(html)) !== null) {
let cover = match[3]
if (!cover.startsWith('http')) {
cover = 'https://www.ykmh.net' + (cover.startsWith('/') ? cover : '/' + cover)
}
comics.push(new Comic({
id: match[2],
title: match[5] || match[4],
cover: cover,
tags: [],
description: ""
}))
}
return comics
}
let comics = parseComicsList(res.body)
let maxPage = 1
let pagePattern = /
]*><\/a>\s*
]*>([\s\S]*?)<\/ul>/g;
let groupMatch;
while ((groupMatch = chapterGroupsPattern.exec(html)) !== null) {
try {
if (groupMatch && groupMatch[1] && groupMatch[3]) {
let groupTitle = groupMatch[1].trim();
let groupContent = groupMatch[3];
let groupChapters = new Map();
let chapterPattern = /
]+src="([^"]+)"[^>]*>/g;
let match;
while ((match = imgPattern.exec(html)) !== null) {
let imgSrc = match[1];
if (imgSrc.includes('cover') || imgSrc.includes('avatar') ||
imgSrc.includes('logo') || imgSrc.includes('icon') ||
imgSrc.includes('banner')) {
continue;
}
if (!imgSrc.startsWith('http')) {
imgSrc = 'https://m.ykmh.net' + (imgSrc.startsWith('/') ? imgSrc : '/' + imgSrc);
}
images.push(imgSrc);
}
}
if (images.length === 0) {
let containerPattern = /
]+src="([^"]+)"/g;
let match;
while ((match = imgPattern.exec(containerHtml)) !== null) {
let imgSrc = match[1];
if (!imgSrc.startsWith('http')) {
imgSrc = 'https://m.ykmh.net' + (imgSrc.startsWith('/') ? imgSrc : '/' + imgSrc);
}
images.push(imgSrc);
}
}
}
return images;
}
try {
let images = parseChapterImages(res.body);
if (images.length === 0) {
console.warn("未找到章节图片,可能需要进一步的页面解析");
}
return { images: images || [] };
} catch (error) {
throw `解析章节图片失败: ${error.message || error}`;
}
},
onClickTag: (namespace, tag) => {
if (namespace === "标签") {
let r_tag = YKMHSource.category_param_dict[tag];
return {
action: 'category',
keyword: `${tag}`,
param: `${r_tag}`,
}
}
throw "未支持此类Tag检索"
}
}
}