diff --git a/package-lock.json b/package-lock.json index f4479c1..f057a47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -283,7 +283,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz", "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==", "dev": true, - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -327,7 +326,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz", "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==", "dev": true, - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1069,7 +1067,6 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz", "integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==", "dev": true, - "peer": true, "dependencies": { "@babel/runtime": "^7.26.0", "@mui/core-downloads-tracker": "^6.1.9", @@ -3005,7 +3002,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.66.tgz", "integrity": "sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==", "devOptional": true, - "peer": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -3017,7 +3013,6 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", "devOptional": true, - "peer": true, "dependencies": { "@types/react": "*" } @@ -3090,7 +3085,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", "dev": true, - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "7.14.1", "@typescript-eslint/types": "7.14.1", @@ -3306,7 +3300,6 @@ "version": "8.12.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4966,7 +4959,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7575,7 +7567,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -7587,7 +7578,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -7607,7 +7597,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dev": true, - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.3", "use-sync-external-store": "^1.0.0" @@ -7760,8 +7749,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "dev": true, - "peer": true + "dev": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -8586,7 +8574,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8658,7 +8645,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8848,7 +8834,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -8954,7 +8939,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -9349,7 +9333,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.5.tgz", "integrity": "sha512-6zeCUxUH+EPF1s+YF/2hPVODeV/7V07YU5x+2tfuRL8MdW6rv5vb2+CBEGTGwBdux0OIERcOS+RzxeK80k2DsQ==", "dev": true, - "peer": true, "requires": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -9385,7 +9368,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.5.tgz", "integrity": "sha512-gnOQ+nGLPvDXgIx119JqGalys64lhMdnNQA9TMxhDA4K0Hq5+++OE20Zs5GxiCV9r814xQ2K5WmtofSpHVW6BQ==", "dev": true, - "peer": true, "requires": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -9774,7 +9756,6 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.9.tgz", "integrity": "sha512-NwqIN0bdsgzSbZd5JFcC+2ez0XW/XNs8uiV2PDHrqQ4qf/FEasFJG1z6g8JbCN0YlTrHZekVb17X0Fv0qcYJfQ==", "dev": true, - "peer": true, "requires": { "@babel/runtime": "^7.26.0", "@mui/core-downloads-tracker": "^6.1.9", @@ -10753,7 +10734,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.66.tgz", "integrity": "sha512-OYTmMI4UigXeFMF/j4uv0lBBEbongSgptPrHBxqME44h9+yNov+oL6Z3ocJKo0WyXR84sQUNeyIp9MRfckvZpg==", "devOptional": true, - "peer": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -10765,7 +10745,6 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz", "integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==", "devOptional": true, - "peer": true, "requires": { "@types/react": "*" } @@ -10822,7 +10801,6 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz", "integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==", "dev": true, - "peer": true, "requires": { "@typescript-eslint/scope-manager": "7.14.1", "@typescript-eslint/types": "7.14.1", @@ -10951,8 +10929,7 @@ "acorn": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", - "peer": true + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==" }, "acorn-jsx": { "version": "5.3.2", @@ -12154,7 +12131,6 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, - "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -13890,7 +13866,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "peer": true, "requires": { "loose-envify": "^1.1.0" } @@ -13899,7 +13874,6 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "peer": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -13916,7 +13890,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dev": true, - "peer": true, "requires": { "@types/use-sync-external-store": "^0.0.3", "use-sync-external-store": "^1.0.0" @@ -13996,8 +13969,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "dev": true, - "peer": true + "dev": true }, "redux-thunk": { "version": "3.1.0", @@ -14567,8 +14539,7 @@ "picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "peer": true + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" } } }, @@ -14617,8 +14588,7 @@ "typescript": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "peer": true + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==" }, "typescript-eslint": { "version": "7.14.1", @@ -14742,7 +14712,6 @@ "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", - "peer": true, "requires": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -14762,8 +14731,7 @@ "picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "peer": true + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==" } } }, diff --git a/plugins/chinese/69xinshu.ts b/plugins/chinese/69xinshu.ts deleted file mode 100644 index a730c86..0000000 --- a/plugins/chinese/69xinshu.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { load as parseHTML } from 'cheerio'; -import { fetchText } from '@/lib/fetch'; -import { FilterTypes, Filters } from '@libs/filterInputs'; -import { Plugin } from '@/types/plugin'; -import { encode } from 'urlencode'; -import { NovelStatus } from '@libs/novelStatus'; - -class XinShu69 implements Plugin.PluginBase { - id = '69xinshu'; - name = '69书吧'; - icon = 'src/cn/69xinshu/icon.png'; - site = 'https://69shu.biz'; - version = '0.1.2'; - - async popularNovels( - pageNo: number, - { filters }: Plugin.PopularNovelsOptions, - ): Promise { - let url: string; - if (pageNo === 1) { - url = `${this.site}/novels/class/${filters.class.value}.htm`; - } else { - url = `${this.site}/ajax_novels/class/${filters.class.value}/${pageNo}.htm`; - } - - const body = await fetchText(url, {}, 'gbk'); - if (body === '') throw Error('无法获取小说列表,请检查网络'); - - const loadedCheerio = parseHTML(body); - - const novels: Plugin.NovelItem[] = []; - - const novelsList = - pageNo === 1 - ? loadedCheerio('.newlistbox > ul > li') - : loadedCheerio('li'); - - novelsList.each((i, e) => { - const novelUrl = loadedCheerio(e).find('div > h3 > a').attr('href'); - if (novelUrl) { - const novelName = loadedCheerio(e).find('div > h3 > a').text(); - const novelCover = loadedCheerio(e).find('a > img').attr('data-src'); - - const novel = { - name: novelName, - cover: novelCover, - path: novelUrl.replace(this.site, ''), - }; - - novels.push(novel); - } - }); - - return novels; - } - - async parseNovel(novelPath: string): Promise { - const url = this.site + novelPath; - - const body = await fetchText(url, {}, 'gbk'); - if (body === '') throw Error('无法获取小说内容,请检查网络'); - - const loadedCheerio = parseHTML(body); - - const novel: Plugin.SourceNovel = { - path: novelPath, - chapters: [], - name: loadedCheerio('h1 > a').text(), - }; - - novel.cover = loadedCheerio('div.bookimg2 > img').attr('src'); - - novel.summary = loadedCheerio('div.navtxt').text().trim(); - - const bookInfo = loadedCheerio('div.booknav2').text(); - - const authorMatch = bookInfo.match(/作者:(.*)/); - if (authorMatch) { - novel.author = authorMatch[1]; - } - - novel.artist = undefined; - - novel.status = bookInfo.includes('连载') - ? NovelStatus.Ongoing - : NovelStatus.Completed; - - const genresMatch = bookInfo.match(/分类:(.*)/); - if (genresMatch) { - novel.genres = genresMatch[1]; - } - - // Table of Content is on a different page than the summary page - const chapters: Plugin.ChapterItem[] = []; - - const chaptersUrl = loadedCheerio('a.more-btn').attr('href'); - if (chaptersUrl) { - const chaptersBody = await fetchText(chaptersUrl, {}, 'gbk'); - - const chaptersLoadedCheerio = parseHTML(chaptersBody); - - chaptersLoadedCheerio('li').each((i, e) => { - const chapterUrl = chaptersLoadedCheerio(e).find('a').attr('href'); - - if (chapterUrl?.startsWith('https://')) { - const chapterName = chaptersLoadedCheerio(e).find('a').text().trim(); - - chapters.push({ - name: chapterName, - path: chapterUrl.replace(this.site, ''), - }); - } - }); - } - - novel.chapters = chapters; - - return novel; - } - - async parseChapter(chapterPath: string): Promise { - const body = await fetchText(this.site + chapterPath, {}, 'gbk'); - - const loadedCheerio = parseHTML(body); - - const chapterText = (loadedCheerio('div.txtnav').prop('innerText') ?? '') - .split('\n') - // remove empty lines - .map((line: string) => line.trim()) - .filter((line: string) => line !== '') - // remove the first two lines which are the chapter name and author name - .slice(2) - .map((line: string) => `

${line}

`) - .join('\n'); - - return chapterText; - } - - async searchNovels( - searchTerm: string, - pageNo: number, - ): Promise { - if (pageNo > 1) return []; - - const searchUrl = `${this.site}/modules/article/search.php`; - const formData = new FormData(); - formData.append('searchkey', encode(searchTerm, 'gbk')); - formData.append('searchtype', 'all'); - - const body = await fetchText( - searchUrl, - { method: 'post', body: formData }, - 'gbk', - ); - if (body === '') throw Error('无法获取搜索结果,请检查网络'); - const loadedCheerio = parseHTML(body); - - const novels: Plugin.NovelItem[] = []; - - loadedCheerio('.newbox > ul > li').each((i, e) => { - const novelUrl = loadedCheerio(e).find('a').attr('href')!; - const novelName = loadedCheerio(e).find('div.newnav > h3').text(); - const novelCover = loadedCheerio(e).find('img').attr('data-src'); - - const novel = { - name: novelName, - path: novelUrl.replace(this.site, ''), - cover: novelCover, - }; - - novels.push(novel); - }); - - return novels; - } - - filters = { - class: { - label: '分类', - value: '0', - options: [ - { label: '全部分类', value: '0' }, - { label: '言情小说', value: '3' }, - { label: '玄幻魔法', value: '1' }, - { label: '修真武侠', value: '2' }, - { label: '穿越时空', value: '11' }, - { label: '都市小说', value: '9' }, - { label: '历史军事', value: '4' }, - { label: '游戏竞技', value: '5' }, - { label: '科幻空间', value: '6' }, - { label: '悬疑惊悚', value: '7' }, - { label: '同人小说', value: '8' }, - { label: '官场职场', value: '10' }, - { label: '青春校园', value: '12' }, - ], - type: FilterTypes.Picker, - }, - } satisfies Filters; -} - -export default new XinShu69(); diff --git a/plugins/chinese/Quanben.ts b/plugins/chinese/Quanben.ts index fced16d..fd1bff9 100644 --- a/plugins/chinese/Quanben.ts +++ b/plugins/chinese/Quanben.ts @@ -1,53 +1,44 @@ import { Plugin } from '@/types/plugin'; import { FilterTypes, Filters } from '@libs/filterInputs'; -import { fetchApi, fetchFile } from '@/lib/fetch'; +import { fetchApi } from '@/lib/fetch'; import { NovelStatus } from '@libs/novelStatus'; import { load as parseHTML } from 'cheerio'; import { defaultCover } from '@libs/defaultCover'; -const getStandardNovelPath = (url: string | undefined): string | undefined => { +const parseUrl = (url?: string): URL | undefined => { if (!url) return undefined; try { - const parsedUrl = new URL(url); - const match = parsedUrl.pathname.match(/^(\/amp)?(\/n\/[^\/]+\/)/); - return match?.[2]; - } catch (error) { + return new URL(url, 'https://www.quanben.io'); + } catch { return undefined; } }; -const getChapterFileName = (url: string | undefined): string | undefined => { - if (!url) return undefined; - try { - const parsedUrl = new URL(url); - const pathParts = parsedUrl.pathname.split('/'); - const fileName = pathParts[pathParts.length - 1]; - if (fileName && /^\d+\.html$/.test(fileName)) { - return fileName; - } - return undefined; - } catch (error) { - return undefined; - } +const getStandardNovelPath = (url?: string): string | undefined => { + const parsedUrl = parseUrl(url); + if (!parsedUrl) return undefined; + const match = parsedUrl.pathname.match(/^(\/amp)?(\/n\/[^\/]+\/)/); + return match?.[2]; +}; + +const getChapterFileName = (url?: string): string | undefined => { + const parsedUrl = parseUrl(url); + if (!parsedUrl) return undefined; + const fileName = parsedUrl.pathname.split('/').pop(); + if (fileName && /^\d+\.html$/.test(fileName)) return fileName; + return undefined; }; const makeAbsolute = ( - relativeUrl: string | undefined, - baseUrl: string, + relativeUrl?: string, + baseUrl?: string, ): string | undefined => { - if (!relativeUrl) return undefined; + if (!relativeUrl || !baseUrl) return undefined; try { - if (relativeUrl.startsWith('//')) { - return 'https:' + relativeUrl; - } - if ( - relativeUrl.startsWith('http://') || - relativeUrl.startsWith('https://') - ) { - return relativeUrl; - } + if (relativeUrl.startsWith('//')) return 'https:' + relativeUrl; + if (/^https?:\/\//.test(relativeUrl)) return relativeUrl; return new URL(relativeUrl, baseUrl).href; - } catch (e) { + } catch { return undefined; } }; @@ -56,357 +47,230 @@ class QuanbenPlugin implements Plugin.PluginBase { id = 'quanben'; name = 'Quanben'; site = 'https://www.quanben.io/'; - version = '1.0.0'; + version = '1.0.1'; icon = 'src/cn/quanben/icon.png'; defaultCover = defaultCover; - filters = {} satisfies Filters; + // filters + filters = { + genre: { + label: '分类', + value: 'all', + options: [ + { label: '全部', value: 'all' }, + { label: '玄幻', value: 'xuanhuan' }, + { label: '都市', value: 'dushi' }, + { label: '言情', value: 'yanqing' }, + { label: '穿越', value: 'chuanyue' }, + { label: '青春', value: 'qingchun' }, + { label: '仙侠', value: 'xianxia' }, + { label: '灵异', value: 'lingyi' }, + { label: '悬疑', value: 'xuanyi' }, + { label: '历史', value: 'lishi' }, + { label: '军事', value: 'junshi' }, + { label: '游戏', value: 'youxi' }, + { label: '竞技', value: 'jingji' }, + { label: '科幻', value: 'kehuan' }, + { label: '职场', value: 'zhichang' }, + { label: '官场', value: 'guanchang' }, + { label: '现言', value: 'xianyan' }, + { label: '耽美', value: 'danmei' }, + { label: '其它', value: 'qita' }, + ], + type: FilterTypes.Picker, + }, + } satisfies Filters; - async popularNovels(_pageNo: number): Promise { - const url = this.site + 'amp/'; - const result = await fetchApi(url); - if (!result.ok) { - throw new Error( - `[Quanben] Failed to fetch AMP popular novels page: ${url} - Status: ${result.status}`, - ); - } - const body = await result.text(); - const $ = parseHTML(body); + // homepage, when you first open the extension (with the applied filters if any) + async popularNovels( + _pageNo: number, + { filters }: Plugin.PopularNovelsOptions, + ): Promise { + const url = + filters.genre.value === 'all' + ? this.site + : `${this.site}c/${filters.genre.value}.html`; + const res = await fetchApi(url); + if (!res.ok) + throw new Error(`[Quanben] Failed to fetch: ${url} - ${res.status}`); + + const $ = parseHTML(await res.text()); const novels: Plugin.NovelItem[] = []; - const processedAmpPaths = new Set(); - $('div.box').each((_i, box) => { - const $box = $(box); + $('div.list2').each((_i, list2) => { + const $list2 = $(list2); + const $link = $list2.find('h3 > a').first(); + const href = $link.attr('href')?.trim(); + const name = $link.text().trim(); + const rawCover = + $list2.find('img').attr('src')?.trim() || + $list2.find('img').attr('data-src')?.trim(); + const cover = makeAbsolute(rawCover, this.site) || this.defaultCover; - // 1. Process the featured novel (div.list2) if it exists - const $featured = $box.find('div.list2'); - if ($featured.length > 0) { - const $link = $featured.find('h3 > a'); - const ampPath = $link.attr('href')?.trim(); - const name = $link.text().trim(); - const rawCoverSrc = $featured.find('amp-img').attr('src')?.trim(); - const cover = makeAbsolute(rawCoverSrc, this.site) || this.defaultCover; - - if (ampPath && name && !processedAmpPaths.has(ampPath)) { - novels.push({ name, path: ampPath, cover }); - processedAmpPaths.add(ampPath); - } + if (href && name) { + const path = getStandardNovelPath(href); + if (path) novels.push({ name, path, cover }); } + }); - // 2. Process novels in the list (ul.list) - $box.find('ul.list li').each((_j, listItem) => { - const $listItem = $(listItem); - const $link = $listItem.find('a'); - const ampPath = $link.attr('href')?.trim(); - const name = $link.find('span').first().text().trim(); // Name is inside a span within the link + // only first entry bcs the others dont have an image + $('ul.list').each((_i, ul) => { + const $firstLi = $(ul).find('li').first(); + const $a = $firstLi.find('a').first(); + const href = $a.attr('href')?.trim(); + const name = + $a.text().trim() || $firstLi.find('span.author').text().trim(); + const cover = this.defaultCover; - if (ampPath && name && !processedAmpPaths.has(ampPath)) { - novels.push({ name, path: ampPath, cover: this.defaultCover }); // Use default cover for list items - processedAmpPaths.add(ampPath); - } - }); + if (href && name) { + const path = getStandardNovelPath(href); + if (path) novels.push({ name, path, cover }); + } }); return novels; } + // novel details and metadata async parseNovel(novelPath: string): Promise { - // ** Expects AMP path: /amp/n/novel-name/ ** - if ( - !novelPath || - !novelPath.startsWith('/amp/n/') || - !novelPath.endsWith('/') - ) { - throw new Error( - `[Quanben parseNovel] Invalid novelPath received: "${novelPath}". Expected AMP format: "/amp/n/novel-name/"`, - ); - } + const standardPath = novelPath.replace(/^\/amp/, ''); + if (!standardPath.startsWith('/n/') || !standardPath.endsWith('/')) + throw new Error(`[Quanben parseNovel] Invalid path: ${novelPath}`); - // Construct full AMP novel URL - const fullNovelUrl = makeAbsolute(novelPath, this.site); - if (!fullNovelUrl) { - throw new Error( - `[Quanben parseNovel] Could not construct full AMP novel URL from path: ${novelPath}`, - ); - } + const fullUrl = makeAbsolute(standardPath, this.site); + if (!fullUrl) + throw new Error(`[Quanben parseNovel] Could not construct full URL`); - // 1. Fetch AMP Novel Page HTML - const novelPageResult = await fetchApi(fullNovelUrl); - if (!novelPageResult.ok) { - throw new Error( - `[Quanben parseNovel] Failed to fetch AMP novel page: ${fullNovelUrl} - Status: ${novelPageResult.status}`, - ); - } - const novelPageHtml = await novelPageResult.text(); - const $ = parseHTML(novelPageHtml); + const res = await fetchApi(fullUrl); + if (!res.ok) + throw new Error(`[Quanben parseNovel] Failed to fetch: ${fullUrl}`); - // 2. Parse Novel Details from AMP page - **Refined Selectors** - const $infoBox = $('div.list2'); // Base element for many details - const $descriptionBox = $('div.description'); // Separate element for summary + const $ = parseHTML(await res.text()); + const $info = $('div.list2').first(); + const $desc = $('div.description').first(); const novel: Plugin.SourceNovel = { - path: novelPath, // Use the input AMP path - name: - $infoBox.find('h3').text().trim() || // **Use h3 inside list2** - $('h1[itemprop="name headline"]').text().trim() || // Fallback H1 - 'Unknown Novel Name', + path: standardPath, + name: $info.find('h3').text().trim() || 'Unknown Novel', cover: - makeAbsolute($infoBox.find('amp-img').attr('src'), this.site) || // **amp-img inside list2** + makeAbsolute($info.find('img').attr('src'), this.site) || this.defaultCover, summary: - $descriptionBox.find('p').text().trim() || // **Use p inside div.description** - $descriptionBox.text().trim() || // Fallback to div.description text - undefined, - // Use :contains() for more robust selection within the info box - author: - $infoBox.find("p:contains('作者:') span").text().trim() || undefined, - status: NovelStatus.Unknown, // Parsed below - genres: - $infoBox.find("p:contains('类别:') span").text().trim() || undefined, - chapters: [], // Parsed below + $desc.find('p').text().trim() || $desc.text().trim() || undefined, + author: $info.find("p:contains('作者:') span").text().trim() || undefined, + status: NovelStatus.Unknown, + genres: $info.find("p:contains('类别:') span").text().trim() || undefined, + chapters: await this.parseChapterList(standardPath), }; - // Parse Status from AMP page - const statusText = - $infoBox.find("p:contains('状态:') span").text().trim() || // Try specific span first - $infoBox.text(); // Fallback to full text - if (statusText.includes('完结') || statusText.includes('已完成')) { - novel.status = NovelStatus.Completed; - } else if (statusText.includes('连载中') || statusText.includes('进行中')) { - novel.status = NovelStatus.Ongoing; - } - - // 3. Fetch and Parse Chapter List - novel.chapters = await this.parseChapterList(novelPath); + novel.status = NovelStatus.Completed; return novel; } - // Separate function to handle chapter list parsing - **Using AMP** async parseChapterList(novelPath: string): Promise { - // ** Expects AMP path: /amp/n/novel-name/ ** - if ( - !novelPath || - !novelPath.startsWith('/amp/n/') || - !novelPath.endsWith('/') - ) { - return []; - } + if (!novelPath.startsWith('/n/') || !novelPath.endsWith('/')) return []; - // Construct the AMP chapter list URL - const ampChapterListUrl = makeAbsolute(novelPath + 'list.html', this.site); - if (!ampChapterListUrl) { - return []; - } + const url = makeAbsolute(novelPath + 'list.html', this.site); + if (!url) return []; - const chapterListResult = await fetchApi(ampChapterListUrl); - if (!chapterListResult.ok) { - return []; - } - const chapterListHtml = await chapterListResult.text(); - const $ = parseHTML(chapterListHtml); + const res = await fetchApi(url); + if (!res.ok) return []; + const $ = parseHTML(await res.text()); const chapters: Plugin.ChapterItem[] = []; - // Extract standard novel name from AMP path for chapter path storage - const standardNovelPathMatch = novelPath.match(/(\/n\/[^\/]+\/)/); - if (!standardNovelPathMatch || !standardNovelPathMatch[1]) { - return []; - } - const novelNameOnly = standardNovelPathMatch[1].replace(/^\/n\/|\/$/g, ''); + const novelName = novelPath.match(/\/n\/([^\/]+)\//)?.[1]; + if (!novelName) return []; - // 1. Parse chapters from ALL list3 uls in the AMP HTML $('ul.list3 li a').each((_i, el) => { const $el = $(el); - const chapterName = $el.text().trim(); - const chapterHref = $el.attr('href'); - if (chapterName && chapterHref) { - // URLs in AMP page usually point to the standard chapter URLs - const absoluteUrl = makeAbsolute(chapterHref, this.site); // Use base site URL - const chapterFileName = getChapterFileName(absoluteUrl); - if (chapterFileName) { - // ** Store chapter path in standard format for parseChapter ** - const chapterPathForStorage = novelNameOnly + '/' + chapterFileName; - chapters.push({ - name: chapterName, - path: chapterPathForStorage, - // chapterNumber assigned later - }); - } - } + const name = $el.text().trim(); + const href = $el.attr('href'); + if (!name || !href) return; + + const fileName = getChapterFileName(makeAbsolute(href, this.site)); + if (!fileName) return; + + chapters.push({ + name, + path: `${novelName}/${fileName}`, + }); }); - // 2. Deduplicate chapters based on path - const chapterMap = new Map(); - chapters.forEach(chapter => { - if (!chapterMap.has(chapter.path)) { - chapterMap.set(chapter.path, chapter); - } - }); - const uniqueChapters = Array.from(chapterMap.values()); - - // 3. Sort chapters numerically based on filename + const uniqueChapters = Array.from( + new Map(chapters.map(c => [c.path, c])).values(), + ); uniqueChapters.sort((a, b) => { const numA = parseInt(a.path.match(/(\d+)\.html$/)?.[1] || '0', 10); const numB = parseInt(b.path.match(/(\d+)\.html$/)?.[1] || '0', 10); return numA - numB; }); - // 4. Assign chapter numbers - return uniqueChapters.map((chapter, index) => ({ - ...chapter, - chapterNumber: index + 1, - })); + return uniqueChapters.map((c, idx) => ({ ...c, chapterNumber: idx + 1 })); } async parseChapter(chapterPath: string): Promise { - // ** Expects standard path: novel-name/chapterFileName.html ** - if ( - !chapterPath || - !chapterPath.includes('/') || - chapterPath.endsWith('/') - ) { - throw new Error( - `[Quanben] Invalid chapterPath format received in parseChapter: "${chapterPath}". Expected format: "novel-name/chapterFileName.html"`, - ); - } + if (!chapterPath.includes('/') || chapterPath.endsWith('/')) + throw new Error(`[Quanben] Invalid chapter path: "${chapterPath}"`); - // Construct the standard chapter URL using /n/ prefix - const chapterUrl = `${this.site}n/${chapterPath}`; + const url = `${this.site}n/${chapterPath}`; + const res = await fetchApi(url); + if (!res.ok) throw new Error(`[Quanben] Failed to fetch chapter: ${url}`); - const result = await fetchApi(chapterUrl); - if (!result.ok) { - // Handle potential redirects (e.g., chapter moved) - check Location header if status is 3xx - if (result.status >= 300 && result.status < 400) { - const redirectUrl = result.headers.get('Location'); - if (redirectUrl) { - const absoluteRedirectUrl = makeAbsolute(redirectUrl, chapterUrl); - if (!absoluteRedirectUrl) { - throw new Error( - `[Quanben] Failed to make redirected URL absolute: ${redirectUrl}`, - ); - } - const redirectResult = await fetchApi(absoluteRedirectUrl); - if (!redirectResult.ok) { - throw new Error( - `[Quanben] Failed to fetch redirected chapter content: ${absoluteRedirectUrl} - Status: ${redirectResult.status}`, - ); - } - return this.extractChapterContent( - await redirectResult.text(), - absoluteRedirectUrl, - ); - } - } - throw new Error( - `[Quanben] Failed to fetch chapter content: ${chapterUrl} - Status: ${result.status}`, - ); - } - const body = await result.text(); - return this.extractChapterContent(body, chapterUrl); + return this.extractChapterContent(await res.text()); } // Helper function to extract and clean chapter content from HTML body - private extractChapterContent(body: string, urlForLog: string): string { + private extractChapterContent(body: string): string { const $ = parseHTML(body); - let $content = $('#contentbody'); - if (!$content.length) { - $content = $('#content'); - } - if (!$content.length) { - $content = $('.content'); - } - if (!$content.length) { - return 'Error: Could not find chapter content container.'; - } + let $content = $('#contentbody, #content, .content').first(); + if (!$content.length) return 'Error: Chapter content not found.'; + $content .find( 'script, style, ins, iframe, [class*="ads"], [id*="ads"], [class*="google"], [id*="google"], [class*="recommend"], div[align="center"]', ) .remove(); - $content.find('p').each((_i, el) => { - const $p = $(el); - const pText = $p.text().trim(); - if ( - pText.includes('请记住本书首发域名') || - pText.includes('手机版阅读网址') || - pText.includes('quanben') || - pText.includes('最新网址') || - pText.includes('章节报错') || - pText.match(/app|APP|下载|客户端/) || - pText.length === 0 || - ($p - .html() - ?.replace(/ /g, '') - .trim() === '' && - $p.find('img').length === 0) - ) { - $p.remove(); - } - }); - $content - .contents() - .filter(function () { - return this.type === 'comment'; - }) - .remove(); - let chapterText = $content.html(); - if (!chapterText) { - return 'Error: Chapter content was empty after cleaning.'; - } - chapterText = chapterText.replace(/<\s*p[^>]*>/gi, '\n\n'); - chapterText = chapterText.replace(/<\s*br[^>]*>/gi, '\n'); - chapterText = chapterText.replace(/<[^>]+>/g, ''); - chapterText = parseHTML(`
${chapterText}
`).text(); - chapterText = chapterText.replace(/[\t ]+/g, ' '); - chapterText = chapterText.replace(/\n{3,}/g, '\n\n'); - chapterText = chapterText.trim(); - return chapterText; + + return ( + ($content.html() || '').replace(/[\t ]+/g, ' ').trim() || + 'Error: Chapter content empty.' + ); } - async searchNovels( - searchTerm: string, - _pageNo: number, - ): Promise { - const searchUrl = `${this.site}index.php?c=book&a=search&keywords=${encodeURIComponent(searchTerm)}`; - const result = await fetchApi(searchUrl); - if (!result.ok) { - return []; - } - const body = await result.text(); - const $ = parseHTML(body); + // add search + async searchNovels(searchTerm: string): Promise { + const url = `${this.site}index.php?c=book&a=search&keywords=${encodeURIComponent(searchTerm)}`; + const res = await fetchApi(url); + if (!res.ok) return []; + const $ = parseHTML(await res.text()); const novels: Plugin.NovelItem[] = []; - $('div.list2').each((_i, element) => { - const $el = $(element); - const nameLink = $el.find('h3 > a').first(); - const img = $el.find('img').first(); + $('div.list2').each((_i, el) => { + const $el = $(el); + const $link = $el.find('h3 > a').first(); + const href = $link.attr('href'); + const name = $link.text().trim(); + const cover = makeAbsolute( + $el.find('img').attr('src') || $el.find('img').attr('data-src'), + this.site, + ); - const novelName = nameLink.text().trim(); - const novelHref = nameLink.attr('href'); - const novelCover = img.attr('src') || img.attr('data-src'); - - if (novelHref && novelName) { - const absoluteUrl = makeAbsolute(novelHref, this.site); - const standardPath = getStandardNovelPath(absoluteUrl); - - if (standardPath) { - // **Construct AMP Path for storage** - const ampPath = '/amp' + standardPath; - const absoluteCover = makeAbsolute(novelCover, this.site); + if (href && name) { + const path = getStandardNovelPath(makeAbsolute(href, this.site)); + if (path) novels.push({ - name: novelName, - path: ampPath, // **Store the AMP path** - cover: absoluteCover || this.defaultCover, + name, + path: '/amp' + path, + cover: cover || this.defaultCover, }); - } } }); return novels; } - // Use fetchApi for fetchImage as it handles potential errors and returns Response async fetchImage(url: string): Promise { return fetchApi(url); } diff --git a/plugins/index.ts b/plugins/index.ts index 1497bd3..08f042a 100644 --- a/plugins/index.ts +++ b/plugins/index.ts @@ -11,241 +11,240 @@ import p_8 from '@plugins/arabic/dilartube'; import p_9 from '@plugins/arabic/rewayatclub'; import p_10 from '@plugins/arabic/sunovels'; import p_11 from '@plugins/chinese/69shu'; -import p_12 from '@plugins/chinese/69xinshu'; -import p_13 from '@plugins/chinese/Quanben'; -import p_14 from '@plugins/chinese/ixdzs8'; -import p_15 from '@plugins/chinese/linovel'; -import p_16 from '@plugins/chinese/linovelib'; -import p_17 from '@plugins/chinese/linovelib_tw'; -import p_18 from '@plugins/chinese/novel543'; -import p_19 from '@plugins/english/AllNovelFull[readnovelfull]'; -import p_20 from '@plugins/english/AllNovel[readnovelfull]'; -import p_21 from '@plugins/english/ArcaneTranslations[lightnovelwp]'; -import p_22 from '@plugins/english/BelleReservoir[madara]'; -import p_23 from '@plugins/english/BoxNovel[readnovelfull]'; -import p_24 from '@plugins/english/CPUnovel[lightnovelwp]'; -import p_25 from '@plugins/english/CitrusAurora[madara]'; -import p_26 from '@plugins/english/CoralBoutique[madara]'; -import p_27 from '@plugins/english/DaoNovel[madara]'; -import p_28 from '@plugins/english/DaoTranslate[lightnovelwp]'; -import p_29 from '@plugins/english/DaoistQuest[fictioneer]'; -import p_30 from '@plugins/english/DearestRosalie[fictioneer]'; -import p_31 from '@plugins/english/DragonTea[madara]'; -import p_32 from '@plugins/english/Dragonholic[madara]'; -import p_33 from '@plugins/english/DuskBlossoms[madara]'; -import p_34 from '@plugins/english/ElloTL[lightnovelwp]'; -import p_35 from '@plugins/english/Eternalune[madara]'; -import p_36 from '@plugins/english/EtudeTranslations[madara]'; -import p_37 from '@plugins/english/FanNovel[readwn]'; -import p_38 from '@plugins/english/FansMTL[readwn]'; -import p_39 from '@plugins/english/FansTranslations[madara]'; -import p_40 from '@plugins/english/FirstKissNovel[madara]'; -import p_41 from '@plugins/english/Foxaholic[madara]'; -import p_42 from '@plugins/english/FreeWebNovel[readnovelfull]'; -import p_43 from '@plugins/english/GalaxyTranslations[madara]'; -import p_44 from '@plugins/english/Guavaread[madara]'; -import p_45 from '@plugins/english/HiraethTranslation[madara]'; -import p_46 from '@plugins/english/HotNovelPub[hotnovelpub]'; -import p_47 from '@plugins/english/Ippotranslations[lightnovelwp]'; -import p_48 from '@plugins/english/KeopiTranslations[lightnovelwp]'; -import p_49 from '@plugins/english/KnoxT[lightnovelwp]'; -import p_50 from '@plugins/english/LazyGirlTranslations[lightnovelwp]'; -import p_51 from '@plugins/english/LibRead[readnovelfull]'; -import p_52 from '@plugins/english/LightNovelCave[lightnovelworld]'; -import p_53 from '@plugins/english/LightNovelHeaven[madara]'; -import p_54 from '@plugins/english/LightNovelPlus[readnovelfull]'; -import p_55 from '@plugins/english/LightNovelPubVip[lightnovelworld]'; -import p_56 from '@plugins/english/LightNovelUpdates[madara]'; -import p_57 from '@plugins/english/LightNovelWord[lightnovelworld]'; -import p_58 from '@plugins/english/LilyontheValley[fictioneer]'; -import p_59 from '@plugins/english/Ltnovel[readwn]'; -import p_60 from '@plugins/english/LunarLetters[madara]'; -import p_61 from '@plugins/english/MTLNovel[madara]'; -import p_62 from '@plugins/english/MTLNovel[mtlnovel]'; -import p_63 from '@plugins/english/Meownovel[madara]'; -import p_64 from '@plugins/english/MoonlightNovels[lightnovelwp]'; -import p_65 from '@plugins/english/MostNovel[madara]'; -import p_66 from '@plugins/english/MysticalSeries[madara]'; -import p_67 from '@plugins/english/NeoSekaiTranslations[madara]'; -import p_68 from '@plugins/english/NitroManga[madara]'; -import p_69 from '@plugins/english/NobleMTL[lightnovelwp]'; -import p_70 from '@plugins/english/NoiceTranslations[madara]'; -import p_71 from '@plugins/english/NovelBin[readnovelfull]'; -import p_72 from '@plugins/english/NovelCool[novelcool]'; -import p_73 from '@plugins/english/NovelFull[readnovelfull]'; -import p_74 from '@plugins/english/NovelLib[fictioneer]'; -import p_75 from '@plugins/english/NovelMultiverse[madara]'; -import p_76 from '@plugins/english/NovelOnline'; -import p_77 from '@plugins/english/NovelTranslate[madara]'; -import p_78 from '@plugins/english/NovelsKnight[lightnovelwp]'; -import p_79 from '@plugins/english/PandaMachineTranslations[lightnovelwp]'; -import p_80 from '@plugins/english/PastelTales[madara]'; -import p_81 from '@plugins/english/PenguinSquad[fictioneer]'; -import p_82 from '@plugins/english/Prizma[fictioneer]'; -import p_83 from '@plugins/english/Ranobes[ranobes]'; -import p_84 from '@plugins/english/Ranovel[madara]'; -import p_85 from '@plugins/english/ReadFanfic[madara]'; -import p_86 from '@plugins/english/ReadNovelFull[readnovelfull]'; -import p_87 from '@plugins/english/RequiemTranslations[lightnovelwp]'; -import p_88 from '@plugins/english/SalmonLatte[madara]'; -import p_89 from '@plugins/english/SleepyTranslations[madara]'; -import p_90 from '@plugins/english/SonicMTL[madara]'; -import p_91 from '@plugins/english/SrankManga[madara]'; -import p_92 from '@plugins/english/StorySeedling'; -import p_93 from '@plugins/english/SweetEscape[madara]'; -import p_94 from '@plugins/english/SystemTranslation[lightnovelwp]'; -import p_95 from '@plugins/english/TranslatinOtaku[madara]'; -import p_96 from '@plugins/english/TranslationWeaver[lightnovelwp]'; -import p_97 from '@plugins/english/UniversalNovel[lightnovelwp]'; -import p_98 from '@plugins/english/VandyTranslate[lightnovelwp]'; -import p_99 from '@plugins/english/VioletLily[madara]'; -import p_100 from '@plugins/english/WebNovelLover[madara]'; -import p_101 from '@plugins/english/WebNovelPub[lightnovelworld]'; -import p_102 from '@plugins/english/WebNovelTranslation[madara]'; -import p_103 from '@plugins/english/WhiteMoonlightNovels[lightnovelwp]'; -import p_104 from '@plugins/english/WooksTeahouse[madara]'; -import p_105 from '@plugins/english/WordExcerpt[madara]'; -import p_106 from '@plugins/english/WuxiaSpace[readwn]'; -import p_107 from '@plugins/english/WuxiaV[readwn]'; -import p_108 from '@plugins/english/WuxiaWorldSite[madara]'; -import p_109 from '@plugins/english/Wuxiabox[readwn]'; -import p_110 from '@plugins/english/Wuxiafox[readwn]'; -import p_111 from '@plugins/english/ZetroTranslation[madara]'; -import p_112 from '@plugins/english/ao3'; -import p_113 from '@plugins/english/bestlightnovel'; -import p_114 from '@plugins/english/chrysanthemumgarden'; -import p_115 from '@plugins/english/divinedaolibrary'; -import p_116 from '@plugins/english/dreambigtl'; -import p_117 from '@plugins/english/earlynovel'; -import p_118 from '@plugins/english/faqwikius'; -import p_119 from '@plugins/english/fenrirrealm'; -import p_120 from '@plugins/english/fictionzone'; -import p_121 from '@plugins/english/foxteller'; -import p_122 from '@plugins/english/genesis'; -import p_123 from '@plugins/english/inkitt'; -import p_124 from '@plugins/english/kdtnovels'; -import p_125 from '@plugins/english/lightnovelpub'; -import p_126 from '@plugins/english/lightnoveltranslation'; -import p_127 from '@plugins/english/lnmtl'; -import p_128 from '@plugins/english/mtlreader'; -import p_129 from '@plugins/english/mvlempyr'; -import p_130 from '@plugins/english/novelbuddy'; -import p_131 from '@plugins/english/novelfire'; -import p_132 from '@plugins/english/novelhall'; -import p_133 from '@plugins/english/novelight'; -import p_134 from '@plugins/english/novelupdates'; -import p_135 from '@plugins/english/pawread'; -import p_136 from '@plugins/english/rainofsnow'; -import p_137 from '@plugins/english/readfrom'; -import p_138 from '@plugins/english/readlitenovel'; -import p_139 from '@plugins/english/reaperscans'; -import p_140 from '@plugins/english/relibrary'; -import p_141 from '@plugins/english/royalroad'; -import p_142 from '@plugins/english/scribblehub'; -import p_143 from '@plugins/english/vynovel'; -import p_144 from '@plugins/english/webnovel'; -import p_145 from '@plugins/english/wtrlab'; -import p_146 from '@plugins/english/wuxiaworld'; -import p_147 from '@plugins/french/LighNovelFR[lightnovelwp]'; -import p_148 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; -import p_149 from '@plugins/french/MassNovel[madara]'; -import p_150 from '@plugins/french/WorldNovel[madara]'; -import p_151 from '@plugins/french/chireads'; -import p_152 from '@plugins/french/harkeneliwood'; -import p_153 from '@plugins/french/kisswood'; -import p_154 from '@plugins/french/noveldeglace'; -import p_155 from '@plugins/french/novhell'; -import p_156 from '@plugins/french/phenixscans'; -import p_157 from '@plugins/french/warriorlegendtrad'; -import p_158 from '@plugins/french/wuxialnscantrad'; -import p_159 from '@plugins/french/xiaowaz'; -import p_160 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; -import p_161 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; -import p_162 from '@plugins/indonesian/MeioNovel[madara]'; -import p_163 from '@plugins/indonesian/NovelBookID[madara]'; -import p_164 from '@plugins/indonesian/Risenovel[madara]'; -import p_165 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; -import p_166 from '@plugins/indonesian/WBNovel[madara]'; -import p_167 from '@plugins/indonesian/indowebnovel'; -import p_168 from '@plugins/indonesian/novelringan'; -import p_169 from '@plugins/indonesian/sakuranovel'; -import p_170 from '@plugins/japanese/Syosetu'; -import p_171 from '@plugins/japanese/kakuyomu'; -import p_172 from '@plugins/korean/Agitoon'; -import p_173 from '@plugins/korean/FortuneEternal[madara]'; -import p_174 from '@plugins/multi/komga'; -import p_175 from '@plugins/polish/novelki'; -import p_176 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; -import p_177 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; -import p_178 from '@plugins/portuguese/Kiniga[madara]'; -import p_179 from '@plugins/portuguese/LaNovels[hotnovelpub]'; -import p_180 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; -import p_181 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; -import p_182 from '@plugins/portuguese/blogdoamonnovels'; -import p_183 from '@plugins/portuguese/novelmania'; -import p_184 from '@plugins/portuguese/tsundoku'; -import p_185 from '@plugins/russian/Bookhamster[ifreedom]'; -import p_186 from '@plugins/russian/Erolate[rulate]'; -import p_187 from '@plugins/russian/EzNovels[hotnovelpub]'; -import p_188 from '@plugins/russian/LitSpace'; -import p_189 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; -import p_190 from '@plugins/russian/NovelCool(RU)[novelcool]'; -import p_191 from '@plugins/russian/Ranobes(RU)[ranobes]'; -import p_192 from '@plugins/russian/Rulate[rulate]'; -import p_193 from '@plugins/russian/authortoday'; -import p_194 from '@plugins/russian/bookriver'; -import p_195 from '@plugins/russian/ficbook'; -import p_196 from '@plugins/russian/jaomix'; -import p_197 from '@plugins/russian/neobook'; -import p_198 from '@plugins/russian/novelOvh'; -import p_199 from '@plugins/russian/novelTL'; -import p_200 from '@plugins/russian/ranobehub'; -import p_201 from '@plugins/russian/ranobelib'; -import p_202 from '@plugins/russian/ranoberf'; -import p_203 from '@plugins/russian/renovels'; -import p_204 from '@plugins/russian/ruvers'; -import p_205 from '@plugins/russian/topliba'; -import p_206 from '@plugins/russian/zelluloza'; -import p_207 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; -import p_208 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; -import p_209 from '@plugins/spanish/AnimesHoy12[madara]'; -import p_210 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; -import p_211 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; -import p_212 from '@plugins/spanish/PanchoTranslations[madara]'; -import p_213 from '@plugins/spanish/TC&Sega[lightnovelwp]'; -import p_214 from '@plugins/spanish/TraduccionesAmistosas[madara]'; -import p_215 from '@plugins/spanish/hasutl'; -import p_216 from '@plugins/spanish/novelasligera'; -import p_217 from '@plugins/spanish/novelawuxia'; -import p_218 from '@plugins/spanish/oasistranslations'; -import p_219 from '@plugins/spanish/skynovels'; -import p_220 from '@plugins/spanish/tunovelaligera'; -import p_221 from '@plugins/spanish/yukitls'; -import p_222 from '@plugins/thai/NovelLucky[madara]'; -import p_223 from '@plugins/thai/NovelPDF[madara]'; -import p_224 from '@plugins/turkish/ArazNovel[madara]'; -import p_225 from '@plugins/turkish/EKTAPLAR[madara]'; -import p_226 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; -import p_227 from '@plugins/turkish/MangaTR'; -import p_228 from '@plugins/turkish/NABSCANS[madara]'; -import p_229 from '@plugins/turkish/Namevt[lightnovelwp]'; -import p_230 from '@plugins/turkish/NovelTR[lightnovelwp]'; -import p_231 from '@plugins/turkish/Noveloku[madara]'; -import p_232 from '@plugins/turkish/RagnarScans[madara]'; -import p_233 from '@plugins/turkish/ThNovels[hotnovelpub]'; -import p_234 from '@plugins/turkish/TurkceLightNovels[madara]'; -import p_235 from '@plugins/turkish/WebNovelOku[madara]'; -import p_236 from '@plugins/turkish/epiknovel'; -import p_237 from '@plugins/turkish/kakikata[madara]'; -import p_238 from '@plugins/ukrainian/bakainua'; -import p_239 from '@plugins/ukrainian/smakolykytl'; -import p_240 from '@plugins/ukrainian/uaranobeclub'; -import p_241 from '@plugins/vietnamese/LNHako'; -import p_242 from '@plugins/vietnamese/Truyenconect'; -import p_243 from '@plugins/vietnamese/lightnovelvn'; -import p_244 from '@plugins/vietnamese/nettruyen'; -import p_245 from '@plugins/vietnamese/truyenchu'; -import p_246 from '@plugins/vietnamese/truyenfull'; +import p_12 from '@plugins/chinese/Quanben'; +import p_13 from '@plugins/chinese/ixdzs8'; +import p_14 from '@plugins/chinese/linovel'; +import p_15 from '@plugins/chinese/linovelib'; +import p_16 from '@plugins/chinese/linovelib_tw'; +import p_17 from '@plugins/chinese/novel543'; +import p_18 from '@plugins/english/AllNovelFull[readnovelfull]'; +import p_19 from '@plugins/english/AllNovel[readnovelfull]'; +import p_20 from '@plugins/english/ArcaneTranslations[lightnovelwp]'; +import p_21 from '@plugins/english/BelleReservoir[madara]'; +import p_22 from '@plugins/english/BoxNovel[readnovelfull]'; +import p_23 from '@plugins/english/CPUnovel[lightnovelwp]'; +import p_24 from '@plugins/english/CitrusAurora[madara]'; +import p_25 from '@plugins/english/CoralBoutique[madara]'; +import p_26 from '@plugins/english/DaoNovel[madara]'; +import p_27 from '@plugins/english/DaoTranslate[lightnovelwp]'; +import p_28 from '@plugins/english/DaoistQuest[fictioneer]'; +import p_29 from '@plugins/english/DearestRosalie[fictioneer]'; +import p_30 from '@plugins/english/DragonTea[madara]'; +import p_31 from '@plugins/english/Dragonholic[madara]'; +import p_32 from '@plugins/english/DuskBlossoms[madara]'; +import p_33 from '@plugins/english/ElloTL[lightnovelwp]'; +import p_34 from '@plugins/english/Eternalune[madara]'; +import p_35 from '@plugins/english/EtudeTranslations[madara]'; +import p_36 from '@plugins/english/FanNovel[readwn]'; +import p_37 from '@plugins/english/FansMTL[readwn]'; +import p_38 from '@plugins/english/FansTranslations[madara]'; +import p_39 from '@plugins/english/FirstKissNovel[madara]'; +import p_40 from '@plugins/english/Foxaholic[madara]'; +import p_41 from '@plugins/english/FreeWebNovel[readnovelfull]'; +import p_42 from '@plugins/english/GalaxyTranslations[madara]'; +import p_43 from '@plugins/english/Guavaread[madara]'; +import p_44 from '@plugins/english/HiraethTranslation[madara]'; +import p_45 from '@plugins/english/HotNovelPub[hotnovelpub]'; +import p_46 from '@plugins/english/Ippotranslations[lightnovelwp]'; +import p_47 from '@plugins/english/KeopiTranslations[lightnovelwp]'; +import p_48 from '@plugins/english/KnoxT[lightnovelwp]'; +import p_49 from '@plugins/english/LazyGirlTranslations[lightnovelwp]'; +import p_50 from '@plugins/english/LibRead[readnovelfull]'; +import p_51 from '@plugins/english/LightNovelCave[lightnovelworld]'; +import p_52 from '@plugins/english/LightNovelHeaven[madara]'; +import p_53 from '@plugins/english/LightNovelPlus[readnovelfull]'; +import p_54 from '@plugins/english/LightNovelPubVip[lightnovelworld]'; +import p_55 from '@plugins/english/LightNovelUpdates[madara]'; +import p_56 from '@plugins/english/LightNovelWord[lightnovelworld]'; +import p_57 from '@plugins/english/LilyontheValley[fictioneer]'; +import p_58 from '@plugins/english/Ltnovel[readwn]'; +import p_59 from '@plugins/english/LunarLetters[madara]'; +import p_60 from '@plugins/english/MTLNovel[madara]'; +import p_61 from '@plugins/english/MTLNovel[mtlnovel]'; +import p_62 from '@plugins/english/Meownovel[madara]'; +import p_63 from '@plugins/english/MoonlightNovels[lightnovelwp]'; +import p_64 from '@plugins/english/MostNovel[madara]'; +import p_65 from '@plugins/english/MysticalSeries[madara]'; +import p_66 from '@plugins/english/NeoSekaiTranslations[madara]'; +import p_67 from '@plugins/english/NitroManga[madara]'; +import p_68 from '@plugins/english/NobleMTL[lightnovelwp]'; +import p_69 from '@plugins/english/NoiceTranslations[madara]'; +import p_70 from '@plugins/english/NovelBin[readnovelfull]'; +import p_71 from '@plugins/english/NovelCool[novelcool]'; +import p_72 from '@plugins/english/NovelFull[readnovelfull]'; +import p_73 from '@plugins/english/NovelLib[fictioneer]'; +import p_74 from '@plugins/english/NovelMultiverse[madara]'; +import p_75 from '@plugins/english/NovelOnline'; +import p_76 from '@plugins/english/NovelTranslate[madara]'; +import p_77 from '@plugins/english/NovelsKnight[lightnovelwp]'; +import p_78 from '@plugins/english/PandaMachineTranslations[lightnovelwp]'; +import p_79 from '@plugins/english/PastelTales[madara]'; +import p_80 from '@plugins/english/PenguinSquad[fictioneer]'; +import p_81 from '@plugins/english/Prizma[fictioneer]'; +import p_82 from '@plugins/english/Ranobes[ranobes]'; +import p_83 from '@plugins/english/Ranovel[madara]'; +import p_84 from '@plugins/english/ReadFanfic[madara]'; +import p_85 from '@plugins/english/ReadNovelFull[readnovelfull]'; +import p_86 from '@plugins/english/RequiemTranslations[lightnovelwp]'; +import p_87 from '@plugins/english/SalmonLatte[madara]'; +import p_88 from '@plugins/english/SleepyTranslations[madara]'; +import p_89 from '@plugins/english/SonicMTL[madara]'; +import p_90 from '@plugins/english/SrankManga[madara]'; +import p_91 from '@plugins/english/StorySeedling'; +import p_92 from '@plugins/english/SweetEscape[madara]'; +import p_93 from '@plugins/english/SystemTranslation[lightnovelwp]'; +import p_94 from '@plugins/english/TranslatinOtaku[madara]'; +import p_95 from '@plugins/english/TranslationWeaver[lightnovelwp]'; +import p_96 from '@plugins/english/UniversalNovel[lightnovelwp]'; +import p_97 from '@plugins/english/VandyTranslate[lightnovelwp]'; +import p_98 from '@plugins/english/VioletLily[madara]'; +import p_99 from '@plugins/english/WebNovelLover[madara]'; +import p_100 from '@plugins/english/WebNovelPub[lightnovelworld]'; +import p_101 from '@plugins/english/WebNovelTranslation[madara]'; +import p_102 from '@plugins/english/WhiteMoonlightNovels[lightnovelwp]'; +import p_103 from '@plugins/english/WooksTeahouse[madara]'; +import p_104 from '@plugins/english/WordExcerpt[madara]'; +import p_105 from '@plugins/english/WuxiaSpace[readwn]'; +import p_106 from '@plugins/english/WuxiaV[readwn]'; +import p_107 from '@plugins/english/WuxiaWorldSite[madara]'; +import p_108 from '@plugins/english/Wuxiabox[readwn]'; +import p_109 from '@plugins/english/Wuxiafox[readwn]'; +import p_110 from '@plugins/english/ZetroTranslation[madara]'; +import p_111 from '@plugins/english/ao3'; +import p_112 from '@plugins/english/bestlightnovel'; +import p_113 from '@plugins/english/chrysanthemumgarden'; +import p_114 from '@plugins/english/divinedaolibrary'; +import p_115 from '@plugins/english/dreambigtl'; +import p_116 from '@plugins/english/earlynovel'; +import p_117 from '@plugins/english/faqwikius'; +import p_118 from '@plugins/english/fenrirrealm'; +import p_119 from '@plugins/english/fictionzone'; +import p_120 from '@plugins/english/foxteller'; +import p_121 from '@plugins/english/genesis'; +import p_122 from '@plugins/english/inkitt'; +import p_123 from '@plugins/english/kdtnovels'; +import p_124 from '@plugins/english/lightnovelpub'; +import p_125 from '@plugins/english/lightnoveltranslation'; +import p_126 from '@plugins/english/lnmtl'; +import p_127 from '@plugins/english/mtlreader'; +import p_128 from '@plugins/english/mvlempyr'; +import p_129 from '@plugins/english/novelbuddy'; +import p_130 from '@plugins/english/novelfire'; +import p_131 from '@plugins/english/novelhall'; +import p_132 from '@plugins/english/novelight'; +import p_133 from '@plugins/english/novelupdates'; +import p_134 from '@plugins/english/pawread'; +import p_135 from '@plugins/english/rainofsnow'; +import p_136 from '@plugins/english/readfrom'; +import p_137 from '@plugins/english/readlitenovel'; +import p_138 from '@plugins/english/reaperscans'; +import p_139 from '@plugins/english/relibrary'; +import p_140 from '@plugins/english/royalroad'; +import p_141 from '@plugins/english/scribblehub'; +import p_142 from '@plugins/english/vynovel'; +import p_143 from '@plugins/english/webnovel'; +import p_144 from '@plugins/english/wtrlab'; +import p_145 from '@plugins/english/wuxiaworld'; +import p_146 from '@plugins/french/LighNovelFR[lightnovelwp]'; +import p_147 from '@plugins/french/MTLNovel(FR)[mtlnovel]'; +import p_148 from '@plugins/french/MassNovel[madara]'; +import p_149 from '@plugins/french/WorldNovel[madara]'; +import p_150 from '@plugins/french/chireads'; +import p_151 from '@plugins/french/harkeneliwood'; +import p_152 from '@plugins/french/kisswood'; +import p_153 from '@plugins/french/noveldeglace'; +import p_154 from '@plugins/french/novhell'; +import p_155 from '@plugins/french/phenixscans'; +import p_156 from '@plugins/french/warriorlegendtrad'; +import p_157 from '@plugins/french/wuxialnscantrad'; +import p_158 from '@plugins/french/xiaowaz'; +import p_159 from '@plugins/indonesian/BacaLightNovel[lightnovelwp]'; +import p_160 from '@plugins/indonesian/MTLNovel(ID)[mtlnovel]'; +import p_161 from '@plugins/indonesian/MeioNovel[madara]'; +import p_162 from '@plugins/indonesian/NovelBookID[madara]'; +import p_163 from '@plugins/indonesian/Risenovel[madara]'; +import p_164 from '@plugins/indonesian/SekteNovel[lightnovelwp]'; +import p_165 from '@plugins/indonesian/WBNovel[madara]'; +import p_166 from '@plugins/indonesian/indowebnovel'; +import p_167 from '@plugins/indonesian/novelringan'; +import p_168 from '@plugins/indonesian/sakuranovel'; +import p_169 from '@plugins/japanese/Syosetu'; +import p_170 from '@plugins/japanese/kakuyomu'; +import p_171 from '@plugins/korean/Agitoon'; +import p_172 from '@plugins/korean/FortuneEternal[madara]'; +import p_173 from '@plugins/multi/komga'; +import p_174 from '@plugins/polish/novelki'; +import p_175 from '@plugins/portuguese/BetterNovels[lightnovelwp]'; +import p_176 from '@plugins/portuguese/CentralNovel[lightnovelwp]'; +import p_177 from '@plugins/portuguese/Kiniga[madara]'; +import p_178 from '@plugins/portuguese/LaNovels[hotnovelpub]'; +import p_179 from '@plugins/portuguese/LightNovelBrasil[lightnovelwp]'; +import p_180 from '@plugins/portuguese/MTLNovel(PT)[mtlnovel]'; +import p_181 from '@plugins/portuguese/blogdoamonnovels'; +import p_182 from '@plugins/portuguese/novelmania'; +import p_183 from '@plugins/portuguese/tsundoku'; +import p_184 from '@plugins/russian/Bookhamster[ifreedom]'; +import p_185 from '@plugins/russian/Erolate[rulate]'; +import p_186 from '@plugins/russian/EzNovels[hotnovelpub]'; +import p_187 from '@plugins/russian/LitSpace'; +import p_188 from '@plugins/russian/MTLNovel(RU)[mtlnovel]'; +import p_189 from '@plugins/russian/NovelCool(RU)[novelcool]'; +import p_190 from '@plugins/russian/Ranobes(RU)[ranobes]'; +import p_191 from '@plugins/russian/Rulate[rulate]'; +import p_192 from '@plugins/russian/authortoday'; +import p_193 from '@plugins/russian/bookriver'; +import p_194 from '@plugins/russian/ficbook'; +import p_195 from '@plugins/russian/jaomix'; +import p_196 from '@plugins/russian/neobook'; +import p_197 from '@plugins/russian/novelOvh'; +import p_198 from '@plugins/russian/novelTL'; +import p_199 from '@plugins/russian/ranobehub'; +import p_200 from '@plugins/russian/ranobelib'; +import p_201 from '@plugins/russian/ranoberf'; +import p_202 from '@plugins/russian/renovels'; +import p_203 from '@plugins/russian/ruvers'; +import p_204 from '@plugins/russian/topliba'; +import p_205 from '@plugins/russian/zelluloza'; +import p_206 from '@plugins/russian/СвободныйМирРанобэ[ifreedom]'; +import p_207 from '@plugins/spanish/AllNovelRead[lightnovelwp]'; +import p_208 from '@plugins/spanish/AnimesHoy12[madara]'; +import p_209 from '@plugins/spanish/LightNovelDaily[hotnovelpub]'; +import p_210 from '@plugins/spanish/MTLNovel(ES)[mtlnovel]'; +import p_211 from '@plugins/spanish/PanchoTranslations[madara]'; +import p_212 from '@plugins/spanish/TC&Sega[lightnovelwp]'; +import p_213 from '@plugins/spanish/TraduccionesAmistosas[madara]'; +import p_214 from '@plugins/spanish/hasutl'; +import p_215 from '@plugins/spanish/novelasligera'; +import p_216 from '@plugins/spanish/novelawuxia'; +import p_217 from '@plugins/spanish/oasistranslations'; +import p_218 from '@plugins/spanish/skynovels'; +import p_219 from '@plugins/spanish/tunovelaligera'; +import p_220 from '@plugins/spanish/yukitls'; +import p_221 from '@plugins/thai/NovelLucky[madara]'; +import p_222 from '@plugins/thai/NovelPDF[madara]'; +import p_223 from '@plugins/turkish/ArazNovel[madara]'; +import p_224 from '@plugins/turkish/EKTAPLAR[madara]'; +import p_225 from '@plugins/turkish/KodeksLibrary[lightnovelwp]'; +import p_226 from '@plugins/turkish/MangaTR'; +import p_227 from '@plugins/turkish/NABSCANS[madara]'; +import p_228 from '@plugins/turkish/Namevt[lightnovelwp]'; +import p_229 from '@plugins/turkish/NovelTR[lightnovelwp]'; +import p_230 from '@plugins/turkish/Noveloku[madara]'; +import p_231 from '@plugins/turkish/RagnarScans[madara]'; +import p_232 from '@plugins/turkish/ThNovels[hotnovelpub]'; +import p_233 from '@plugins/turkish/TurkceLightNovels[madara]'; +import p_234 from '@plugins/turkish/WebNovelOku[madara]'; +import p_235 from '@plugins/turkish/epiknovel'; +import p_236 from '@plugins/turkish/kakikata[madara]'; +import p_237 from '@plugins/ukrainian/bakainua'; +import p_238 from '@plugins/ukrainian/smakolykytl'; +import p_239 from '@plugins/ukrainian/uaranobeclub'; +import p_240 from '@plugins/vietnamese/LNHako'; +import p_241 from '@plugins/vietnamese/Truyenconect'; +import p_242 from '@plugins/vietnamese/lightnovelvn'; +import p_243 from '@plugins/vietnamese/nettruyen'; +import p_244 from '@plugins/vietnamese/truyenchu'; +import p_245 from '@plugins/vietnamese/truyenfull'; const PLUGINS: Plugin.PluginBase[] = [ p_0, @@ -494,6 +493,5 @@ const PLUGINS: Plugin.PluginBase[] = [ p_243, p_244, p_245, - p_246, ]; export default PLUGINS; diff --git a/public/static/src/cn/69xinshu/icon.png b/public/static/src/cn/69xinshu/icon.png deleted file mode 100644 index 1411151..0000000 Binary files a/public/static/src/cn/69xinshu/icon.png and /dev/null differ