diff --git a/src/plugins/english/mvlempyr.ts b/src/plugins/english/mvlempyr.ts index a11fa20..c6805ed 100644 --- a/src/plugins/english/mvlempyr.ts +++ b/src/plugins/english/mvlempyr.ts @@ -16,7 +16,6 @@ const parserData: { avgReview?: string; reviewCount?: string; chapterCount?: string; - updated?: string; created?: string; genres?: string; tags?: string; @@ -29,9 +28,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { name = 'MVLEMPYR'; icon = 'src/en/mvlempyr/icon.png'; site = 'https://www.mvlempyr.com/'; - version = '1.0.7'; + version = '1.0.8'; - _chapSite = 'https://chap.mvlempyr.space/'; + _chapSite = 'https://chap.heliosarchive.online/'; _allNovels: (Plugin.NovelItem & ExtraNovelData)[] | undefined; _allNovelsPromise: Promise<(Plugin.NovelItem & ExtraNovelData)[]> | undefined; @@ -44,194 +43,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { throw new Error('Captcha error, please open in webview'); } - parseNovels( - loadedCheerio: CheerioAPI, - nextPageConsumer?: (nextPage: string, pageCount: number) => void, - ) { - this.checkCaptcha(loadedCheerio); - - if (nextPageConsumer) { - const nextPage = loadedCheerio('a.w-pagination-next.next').attr('href'); - if (nextPage) - nextPageConsumer( - nextPage, - parseInt( - loadedCheerio('div.w-page-count.hide').text().split(' / ').pop()!, - ), - ); - } - - return loadedCheerio('.novelcolumn') - .map((i, el) => this.parseNovelHtml(parseHTML(el))) - .toArray(); - } - - parseNovelsFast(body: string) { - const novelInfosStart = body.split('
'); - novelInfosStart.shift(); //remove first element that doesn't have a novel - - const ret = []; - for (const novelInfo of novelInfosStart) { - const realNovelInfo = - novelInfo.split('READ
')[0] + - 'READ'; - - const cheerio = parseHTML(realNovelInfo); - ret.push(this.parseNovelHtml(cheerio)); - } - - return ret; - } - - /** - * Equivalent to parseNovelsFast except uses htmlparser2 instead of cheerio for even more fast-fast - */ - parseNovelsFastNew(body: string) { - const novelInfosStart = body.split('
'); - novelInfosStart.shift(); //remove first element that doesn't have a novel - - const ret = []; - for (const novelInfo of novelInfosStart) { - const realNovelInfo = - novelInfo.split('READ
')[0] + - 'READ'; - - ret.push(this.parseNovelHtmlNew(realNovelInfo)); - } - - // console.log(ret); - return ret; - } - - parseNovelHtmlNew(el: string): Plugin.NovelItem & ExtraNovelData { - parserData.ret = { - name: '', - path: '', - cover: '', - avgReview: '', - reviewCount: '', - chapterCount: '', - updated: '', - created: '', - genres: '', - tags: '', - }; - parserData.inTag = ''; - parserData.depth = 0; - parserData.depthRatingWrapper = 0; - if (!parserData.parser) { - parserData.parser = new Parser({ - onopentag( - name: string, - attribs: Record, - isImplied: boolean, - ) { - if (parserData.depthRatingWrapper) parserData.depthRatingWrapper++; - if (parserData.inTag) { - parserData.depth++; - return; - } - - if (attribs['class']?.includes?.('ratingwrapper')) - parserData.depthRatingWrapper = 1; - - if (name === 'h2' && attribs['fs-cmsfilter-field'] === 'name') - parserData.inTag = 'name'; - if (name === 'a' && !parserData.ret!.path) - parserData.ret!.path = attribs['href'].replace(/^\//, ''); - if (name === 'img' && !parserData.ret!.cover) - parserData.ret!.cover = attribs['src']; - if ( - name === 'div' && - attribs['fs-cmssort-field'] === 'avgr' && - parserData.depthRatingWrapper - ) - parserData.inTag = 'avgReview'; - if ( - name === 'div' && - attribs['fs-cmssort-field'] === 'reviews' && - parserData.depthRatingWrapper - ) - parserData.inTag = 'reviewCount'; - if ( - name === 'div' && - attribs['fs-cmssort-field'] === 'chapter' && - attribs['class']?.includes?.('chapter-count') - ) - parserData.inTag = 'chapterCount'; - if (name === 'div' && attribs['fs-cmssort-field'] === 'update') - parserData.inTag = 'updated'; - if (name === 'div' && attribs['fs-cmssort-field'] === 'crdate') - parserData.inTag = 'created'; - if (name === 'div' && attribs['fs-cmsnest-collection'] === 'genre') - parserData.inTag = 'genres'; - if (name === 'div' && attribs['fs-cmsnest-collection'] === 'tags') - parserData.inTag = 'tags'; - - if (parserData.inTag) { - parserData.depth++; - } - }, - ontext(data: string) { - if (!parserData.inTag) return; - - // @ts-ignore - parserData.ret[parserData.inTag] = - (parserData.ret[parserData.inTag] || '') + data; - }, - onclosetag(name: string, isImplied: boolean) { - if (parserData.depthRatingWrapper) parserData.depthRatingWrapper--; - if (!parserData.inTag) return; - parserData.depth--; - if (!parserData.depth) parserData.inTag = ''; - }, - }); - } - - parserData.parser.reset(); - parserData.parser.write(el); - parserData.parser.end(); - - // @ts-ignore - parserData.ret.avgReview = parseFloat(parserData.ret.avgReview); - // @ts-ignore - parserData.ret.reviewCount = parseFloat(parserData.ret.reviewCount); - // @ts-ignore - parserData.ret.chapterCount = parseFloat(parserData.ret.chapterCount); - // @ts-ignore - parserData.ret.updated = new Date(parserData.ret.updated).getTime(); - // @ts-ignore - parserData.ret.created = new Date(parserData.ret.created).getTime(); - // @ts-ignore - parserData.ret.genres = parserData.ret.genres.split(', '); - // @ts-ignore - parserData.ret.tags = parserData.ret.tags.split(', '); - - // @ts-ignore - return parserData.ret; - } - - parseNovelHtml(el: CheerioAPI) { - return { - name: el('h2[fs-cmsfilter-field="name"]').text(), - path: el('a').attr('href')!.replace(/^\//, ''), - cover: el('img').attr('src'), - avgReview: parseFloat( - el('.ratingwrapper > div[fs-cmssort-field="avgr"]').text(), - ), - reviewCount: parseFloat( - el('.ratingwrapper > div[fs-cmssort-field="reviews"]').text(), - ), - chapterCount: parseFloat( - el('div[fs-cmssort-field="chapter"].chapter-count').text(), - ), - updated: new Date(el('div[fs-cmssort-field="update"]').text()).getTime(), - created: new Date(el('div[fs-cmssort-field="crdate"]').text()).getTime(), - genres: el('div[fs-cmsnest-collection="genre"]').text().split(', '), - tags: el('div[fs-cmsnest-collection="tags"]').text().split(', '), - }; - } - async popularNovels( pageNo: number, { filters }: Plugin.PopularNovelsOptions, @@ -275,25 +86,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { return this.paginate(sorted, pageNo); } - async parseNovelListPage( - url: string, - nextPageConsumer?: (nextPage: string, pageCount: number) => void, - ): Promise<(Plugin.NovelItem & ExtraNovelData)[]> { - const result = await fetchApi(url, { - headers: { - origin2: this.site.replace(/\/$/, ''), - origin: this.site.replace(/\/$/, ''), - }, - }); - const body = await result.text(); - if (!nextPageConsumer) { - return this.parseNovelsFastNew(body); - } - - const loadedCheerio = parseHTML(body); - return this.parseNovels(loadedCheerio, nextPageConsumer); - } - convertNovelId(e: bigint) { let t = 1999999997n; let u = 1n, @@ -323,15 +115,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { 'wp-json/wp/v2/posts?tags=' + newNovelId + '&per_page=500&page=1', - { - headers: { - origin2: this.site.replace(/\/$/, ''), - origin: this.site.replace(/\/$/, ''), - }, - }, ); - const pages = parseInt(firstPostsReq.headers.get('x-wp-totalpages')); + const pages = parseInt(firstPostsReq.headers.get('X-Wp-Totalpages')) || 1; const posts = [ await firstPostsReq.json(), @@ -346,12 +132,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { newNovelId + '&per_page=500&page=' + page, - { - headers: { - origin2: this.site.replace(/\/$/, ''), - origin: this.site.replace(/\/$/, ''), - }, - }, ).then(res => res.json()), ), )), @@ -359,16 +139,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { return { path: novelPath, - name: - loadedCheerio( - '.novelpaewrapper div.image-container.w-embed > img', - ).attr('alt') || 'Untitled', - cover: loadedCheerio( - '.novelpaewrapper div.image-container.w-embed > img', - ).attr('src'), - summary: loadedCheerio('.novelpaewrapper div.synopsis.w-richtext') - .text() - .trim(), + name: loadedCheerio('h1.novel-title').text() || 'Untitled', + cover: loadedCheerio('img.novel-image').attr('src'), + summary: loadedCheerio('div.synopsis.w-richtext').text().trim(), chapters: posts .map(chap => ({ name: chap.acf.ch_name, @@ -378,13 +151,18 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { chapterNumber: chap.acf.chapter_number, })) .reverse(), - status: loadedCheerio( - '.novelpaewrapper div.novelstatustextmedium', - ).text(), - author: loadedCheerio('.novelpaewrapper div.mobileauthorname').text(), - genres: loadedCheerio( - '.novelpaewrapper div.novelgenre.mobile > div > div > a > div', + status: loadedCheerio('.novelstatustextlarge').text(), + author: loadedCheerio( + 'div.additionalinfo.tm10 > div.textwrapper:nth-child(1)', ) + .toArray() + .filter(e => { + return ( + e.children.length == 2 && + e.children[0].children[0].data === 'Author:' + ); + })[0].children[1].children[0].data, + genres: loadedCheerio('.genre-tags') .map((i, el) => loadedCheerio(el).text()) .toArray() .join(','), @@ -436,31 +214,23 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { } async loadAll() { - let pageQueryId; - let pageCount = 1; - const pages = [ - ...(await this.parseNovelListPage( - `${this.site}advance-search`, - (a, b) => { - pageQueryId = a.split('_page=')[0]; - pageCount = b; - }, - )), - ]; - - const followingPages = []; - for (let i = 2; i <= pageCount; i++) { - followingPages.push( - this.parseNovelListPage( - `${this.site}advance-search${pageQueryId}_page=${i}`, - ), - ); - } - - const pagesAwaited = await Promise.all(followingPages); - pagesAwaited.forEach(page => pages.push(...page)); - - return pages; + const data = await fetchApi( + this._chapSite + 'wp-json/wp/v2/mvl-novels?per_page=10000', + ).then(r => r.json()); + // @ts-ignore + return data.map(novel => { + return { + name: novel.name, + path: 'novel/' + novel.slug, + cover: `https://assets.mvlempyr.app/images/600/${novel['novel-code']}.webp`, + avgReview: novel['average-review'], + reviewCount: novel['total-reviews'], + chapterCount: novel['total-chapters'], + created: new Date(novel['created']).getTime(), + genres: novel.genre, + tags: novel.tags, + }; + }); } filters = { @@ -470,7 +240,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase { label: 'Order by', options: [ { label: 'Latest Added', value: 'created' }, - { label: 'Latest Updated', value: 'updated' }, { label: 'Best Rated', value: 'avgReview' }, { label: 'Most Reviewed', value: 'reviewCount' }, { label: 'Chapter Count', value: 'chapterCount' }, @@ -1468,7 +1237,6 @@ type ExtraNovelData = { avgReview: number; reviewCount: number; chapterCount: number; - updated: number; created: number; genres: string[]; tags: string[];