From ee57de1b776ec615619b72772cccc03c97df4ca1 Mon Sep 17 00:00:00 2001 From: Ftbom Date: Sat, 4 May 2024 17:59:54 +0800 Subject: [PATCH] add some manga extensions --- javascript/manga/src/zh/77mh.js | 258 +++++++++++ javascript/manga/src/zh/manhuadb.js | 668 +++++++++++++++++++++++++++ javascript/manga/src/zh/manhuagui.js | 583 +++++++++++++++++++++++ 3 files changed, 1509 insertions(+) create mode 100644 javascript/manga/src/zh/77mh.js create mode 100644 javascript/manga/src/zh/manhuadb.js create mode 100644 javascript/manga/src/zh/manhuagui.js diff --git a/javascript/manga/src/zh/77mh.js b/javascript/manga/src/zh/77mh.js new file mode 100644 index 00000000..6edec437 --- /dev/null +++ b/javascript/manga/src/zh/77mh.js @@ -0,0 +1,258 @@ +const mangayomiSources = [{ + "name": "新新漫画", + "lang": "zh", + "baseUrl": "https://www.77mh.nl", + "apiUrl": "", + "iconUrl": "https://www.77mh.nl/favicon.ico", + "typeSource": "single", + "isManga": true, + "isNsfw": false, + "version": "0.0.1", + "apiUrl": "", + "dateFormat": "", + "dateFormatLocale": "", + "pkgName": "manga/src/zh/77mh.js" + }]; + + class DefaultExtension extends MProvider { + StringResolve1(p, a, c, k, e, d) { + e = function(c) { + return c.toString(36) + }; + if (!''.replace(/^/, String)) { + while (c--) { + d[c.toString(a)] = k[c] || c.toString(a) + } + k = [function(e) { + return d[e] + }]; + e = function() { + return '\\w+' + }; + c = 1 + }; + while (c--) { + if (k[c]) { + p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]) + } + } + return p + } + + StringResolve2(p, a, c, k, e, d) { + e = function(c) { + return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) + }; + if (!''.replace(/^/, String)) { + while (c--) { + d[e(c)] = k[c] || e(c) + } + k = [function(e) { + return d[e] + }]; + e = function() { + return '\\w+' + }; + c = 1 + }; + while (c--) { + if (k[c]) { + p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]) + } + } + return p + } + + async getIndex1(url) { + const res = await new Client().get(url); + const doc = new Document(res.body); + const elements = doc.select("div.ar_list_co li"); + const mangas = []; + for (const element of elements) { + const title = element.selectFirst("span a").text; + const url = element.selectFirst("span a").attr("href"); + const cover = element.selectFirst("img").attr("src"); + mangas.push({ + name: title, + link: url, + imageUrl: cover + }); + } + return { + list: mangas, + hasNextPage: true + }; + + } + + async getIndex2(url) { + const res = await new Client().get(url); + const doc = new Document(res.body); + const elements = doc.select("div.ar_list_co dl"); + const mangas = []; + for (const element of elements) { + const title = element.selectFirst("h1 a").text.replace("", "").replace("", ""); + const url = element.selectFirst("h1 a").attr("href"); + const cover = element.selectFirst("img").attr("src"); + mangas.push({ + name: title, + link: url, + imageUrl: cover + }); + } + return { + list: mangas, + hasNextPage: true + }; + + } + + async getPopular(page) { + return await this.getIndex1(this.source.baseUrl + "/new_coc.html"); + } + + async getLatestUpdates(page) { + return await this.getIndex1(`${this.source.baseUrl}/lianzai/index_${page - 1}.html`); + } + + async search(query, page, filters) { + var url; + if (query == "") { + url = `${this.source.baseUrl}${filters[0]["values"][filters[0]["state"]]["value"]}/index_${page-1}.html` + } else { + url = `${this.source.baseUrl.replace("www","so")}/k.php?k=${query}&p=${page}`; + } + return await this.getIndex2(url); + } + + async getDetail(url) { + const res = await new Client().get(this.source.baseUrl + url); + const doc = new Document(res.body); + const info = doc.selectFirst("div.ar_list_coc"); + const cover = info.selectFirst("img").attr("src"); + const title = info.selectFirst("h1").text; + const info_other = info.selectFirst("ul.ar_list_coc"); + const author = info_other.selectFirst("a").text; + const status_str = info_other.select("a")[1].text; + var status; + if (status_str == "已完结") { + status = 1; + } else { + status = 0; + } + const desc = info.selectFirst("i#det").text; + const elements = doc.select("ul.ar_rlos_bor li a"); + const chapters = []; + for (const element of elements) { + chapters.push({ + name: element.text, + url: element.attr("href") + }); + } + return { + name: title, + imageUrl: cover, + description: desc, + author: author, + status: status, + episodes: chapters + }; + } + + async getPageList(url) { + const preference = new SharedPreferences(); + const image_host = preference.get("imghost"); + const res = await new Client().get(this.source.baseUrl + url); + const strs = res.body.match(/return p}\('(.*?)'.split\('/)[1].split(','); + var result; + try { + result = this.StringResolve1(strs[0], strs[1], strs[2], strs[3].split('|'), 0, {}).replaceAll("'", ""); + } catch { + result = this.StringResolve2(strs[0], strs[1], strs[2], strs[3].split('|'), 0, {}).replaceAll("'", ""); + } + const url_part = result.match(/var img_s=(.*?);var preLink_b/)[1]; + const urls = result.match(/var msg=(.*?);var maxPage/)[1].replaceAll("\\", "").split('|'); + const pages = []; + for (const url of urls) { + pages.push(image_host + `/h${url_part}/` + url); + } + return pages; + } + + getFilterList() { + return [{ + type: "category", + name: "分类", + type_name: "SelectFilter", + values: [{ + value: "/rexue", + name: "热血机战", + type_name: "SelectOption" + }, + { + value: "/kehuan", + name: "科幻未来", + type_name: "SelectOption" + }, + { + value: "/kongbu", + name: "恐怖惊悚", + type_name: "SelectOption" + }, + { + value: "/xuanyi", + name: "推理悬疑", + type_name: "SelectOption" + }, + { + value: "/gaoxiao", + name: "滑稽搞笑", + type_name: "SelectOption" + }, + { + value: "/love", + name: "恋爱生活", + type_name: "SelectOption" + }, + { + value: "/danmei", + name: "耽美人生", + type_name: "SelectOption" + }, + { + value: "/tiyu", + name: "体育竞技", + type_name: "SelectOption" + }, + { + value: "/chunqing", + name: "纯情少女", + type_name: "SelectOption" + }, + { + value: "/qihuan", + name: "魔法奇幻", + type_name: "SelectOption" + }, + { + value: "/wuxia", + name: "武侠经典", + type_name: "SelectOption" + } + ] + }]; + } + + getSourcePreferences() { + return [{ + "key": "imghost", + "listPreference": { + "title": "图片服务器", + "summary": "", + "valueIndex": 0, + "entries": ["服务器1", "服务器2"], + "entryValues": ["https://picsh.77dm.top", "https://imgsh.dm365.top"], + } + }]; + } +} \ No newline at end of file diff --git a/javascript/manga/src/zh/manhuadb.js b/javascript/manga/src/zh/manhuadb.js new file mode 100644 index 00000000..80dcb4b2 --- /dev/null +++ b/javascript/manga/src/zh/manhuadb.js @@ -0,0 +1,668 @@ +const mangayomiSources = [{ + "name": "漫画DB", + "lang": "zh", + "baseUrl": "https://www.manhuadb.com", + "apiUrl": "", + "iconUrl": "https://www.manhuadb.com/assets/www/img/favicon.png", + "typeSource": "single", + "isManga": true, + "isNsfw": false, + "version": "0.0.1", + "dateFormat": "", + "dateFormatLocale": "", + "pkgPath": "manga/src/zh/manhuadb.js" + }]; + + class DefaultExtension extends MProvider { + base64decode(str) { + var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1); + var c1, c2, c3, c4; + var i, len, out; + len = str.length; + i = 0; + out = ""; + while (i < len) { + do { + c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff] + } while (i < len && c1 == -1); + if (c1 == -1) + break; + do { + c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff] + } while (i < len && c2 == -1); + if (c2 == -1) + break; + out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); + do { + c3 = str.charCodeAt(i++) & 0xff; + if (c3 == 61) + return out; + c3 = base64DecodeChars[c3] + } while (i < len && c3 == -1); + if (c3 == -1) + break; + out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); + do { + c4 = str.charCodeAt(i++) & 0xff; + if (c4 == 61) + return out; + c4 = base64DecodeChars[c4] + } while (i < len && c4 == -1); + if (c4 == -1) + break; + out += String.fromCharCode(((c3 & 0x03) << 6) | c4) + } + return out + } + + coverUrlConvert(cover_url) { + if (cover_url.search("com") == -1) { + return this.source.baseUrl + cover_url; + } + return cover_url; + } + + async getMangas(url, search) { + const res = await new Client().get(this.source.baseUrl + url); + const doc = new Document(res.body); + var str; + if (search) { + str = "div.comicbook-index"; + } else { + str = "div.media"; + } + const items = doc.select(str); + const mangas = []; + for (const item of items) { + const cover = this.coverUrlConvert(item.selectFirst("a.d-block img").attr("src")); + var title; + if (search) { + title = item.selectFirst("a.d-block").attr("title"); + } else { + title = item.selectFirst("a.d-block img").attr("alt"); + title = title.replace("的封面图", ""); + } + const url = item.selectFirst("a.d-block").attr("href"); + mangas.push({ + name: title, + link: url, + imageUrl: cover + }); + } + return { + list: mangas, + hasNextPage: true + } + } + + async getPopular(page) { + const res = await new Client().get(this.source.baseUrl); + const doc = new Document(res.body); + const items = doc.select("div.comicbook-index"); + var mangas = []; + for (let item of items) { + const cover = this.coverUrlConvert(item.selectFirst("a img").attr("src")); + const title = item.selectFirst("a img").attr("alt"); + const url = item.selectFirst("a").attr("href") + mangas.push({ + name: title.replace("封面", ""), + link: url, + imageUrl: cover + }); + } + return { + list: mangas, + hasNextPage: false + }; + } + + async getLatestUpdates(page) { + return await this.getMangas(`/manhua/list-page-${page}.html`, false); + } + + async search(query, page, filters) { + if (query == "") { + var locations, readers, status, categories; + for (const filter of filters) { + if (filter["type"] == "locations") { + locations = filter["values"][filter["state"]]["value"]; + } else if (filter["type"] == "readers") { + readers = filter["values"][filter["state"]]["value"]; + } else if (filter["type"] == "status") { + status = filter["values"][filter["state"]]["value"]; + } else if (filter["type"] == "categories") { + categories = filter["values"][filter["state"]]["value"]; + } + } + const url = `/manhua/list${locations}${readers}${status}${categories}-page-${page}.html`; + return await this.getMangas(url.replaceAll("all", ""), false); + } else { + return await this.getMangas(`/search?q=${query}&p=${page}`, true); + } + } + + async getDetail(url) { + const res = await new Client().get(this.source.baseUrl + url); + const doc = new Document(res.body); + const title = doc.selectFirst("h1.comic-title").text; + const cover = this.coverUrlConvert(doc.selectFirst("td.comic-cover img").attr("src")); + const desc = doc.selectFirst("p.comic_story").text; + const author = doc.selectFirst("ul.creators a").text; + var tags = doc.select("ul.tags a").map(e => e.text); + var status = 5; + if (tags[0] == "已完结") { + status = 1; + tags.shift(); + } + if (tags[0] == "连载中") { + status = 0; + tags.shift(); + } + const items = doc.select("ol.links-of-books"); + const episodes = []; + const ep_names = doc.select("span.h3"); + const ep_titles = []; + for (const ep_name of ep_names) { + ep_titles.push(ep_name.text); + } + var index = 0; + for (const lists of items) { + const chapters = lists.select("li"); + for (const chapter of chapters) { + const name = chapter.selectFirst("a").attr("title"); + const url = chapter.selectFirst("a").attr("href"); + episodes.push({ + name: `[[${ep_titles[index]}]]${name}`, + url: url + }); + } + index = index + 1; + } + return { + name: title, + imageUrl: cover, + description: desc, + episodes: episodes, + genre: tags, + author: author, + status: status + }; + } + + async getPageList(url) { + const res = await new Client().get(this.source.baseUrl + url); + const html = res.body; + const doc = new Document(html); + const urls = []; + var script_str = html.match(/