From afea7a6c99cd6c4ec83b9507e4d4ff0d595be63d Mon Sep 17 00:00:00 2001 From: Zion <62723933+jinzong53@users.noreply.github.com> Date: Wed, 23 Jul 2025 10:15:26 +0800 Subject: [PATCH] Add a new resource from ykmh (#107) * 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 --- index.json | 6 + ykmh.js | 883 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 889 insertions(+) create mode 100644 ykmh.js diff --git a/index.json b/index.json index b5dee4a..e46014e 100644 --- a/index.json +++ b/index.json @@ -79,5 +79,11 @@ "fileName": "comick.js", "key": "comick", "version": "1.1.0" + }, + { + "name": "优酷漫画", + "fileName": "ykmh.js", + "key": "ykmh", + "version": "1.0.0" } ] diff --git a/ykmh.js b/ykmh.js new file mode 100644 index 0000000..0e1faa3 --- /dev/null +++ b/ykmh.js @@ -0,0 +1,883 @@ +/** @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检索"
+ }
+ }
+}