Fix mvlempyr again following website recode (#1750)
This commit is contained in:
+34
-266
@@ -16,7 +16,6 @@ const parserData: {
|
|||||||
avgReview?: string;
|
avgReview?: string;
|
||||||
reviewCount?: string;
|
reviewCount?: string;
|
||||||
chapterCount?: string;
|
chapterCount?: string;
|
||||||
updated?: string;
|
|
||||||
created?: string;
|
created?: string;
|
||||||
genres?: string;
|
genres?: string;
|
||||||
tags?: string;
|
tags?: string;
|
||||||
@@ -29,9 +28,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
name = 'MVLEMPYR';
|
name = 'MVLEMPYR';
|
||||||
icon = 'src/en/mvlempyr/icon.png';
|
icon = 'src/en/mvlempyr/icon.png';
|
||||||
site = 'https://www.mvlempyr.com/';
|
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;
|
_allNovels: (Plugin.NovelItem & ExtraNovelData)[] | undefined;
|
||||||
_allNovelsPromise: Promise<(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');
|
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('<div class="novelcolumn">');
|
|
||||||
novelInfosStart.shift(); //remove first element that doesn't have a novel
|
|
||||||
|
|
||||||
const ret = [];
|
|
||||||
for (const novelInfo of novelInfosStart) {
|
|
||||||
const realNovelInfo =
|
|
||||||
novelInfo.split('READ</a></div></div></div>')[0] +
|
|
||||||
'READ</a></div></div></div>';
|
|
||||||
|
|
||||||
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('<div class="novelcolumn">');
|
|
||||||
novelInfosStart.shift(); //remove first element that doesn't have a novel
|
|
||||||
|
|
||||||
const ret = [];
|
|
||||||
for (const novelInfo of novelInfosStart) {
|
|
||||||
const realNovelInfo =
|
|
||||||
novelInfo.split('READ</a></div></div></div>')[0] +
|
|
||||||
'READ</a></div></div></div>';
|
|
||||||
|
|
||||||
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<string, string>,
|
|
||||||
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(
|
async popularNovels(
|
||||||
pageNo: number,
|
pageNo: number,
|
||||||
{ filters }: Plugin.PopularNovelsOptions<Filters>,
|
{ filters }: Plugin.PopularNovelsOptions<Filters>,
|
||||||
@@ -275,25 +86,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
return this.paginate(sorted, pageNo);
|
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) {
|
convertNovelId(e: bigint) {
|
||||||
let t = 1999999997n;
|
let t = 1999999997n;
|
||||||
let u = 1n,
|
let u = 1n,
|
||||||
@@ -323,15 +115,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
'wp-json/wp/v2/posts?tags=' +
|
'wp-json/wp/v2/posts?tags=' +
|
||||||
newNovelId +
|
newNovelId +
|
||||||
'&per_page=500&page=1',
|
'&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 = [
|
const posts = [
|
||||||
await firstPostsReq.json(),
|
await firstPostsReq.json(),
|
||||||
@@ -346,12 +132,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
newNovelId +
|
newNovelId +
|
||||||
'&per_page=500&page=' +
|
'&per_page=500&page=' +
|
||||||
page,
|
page,
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
origin2: this.site.replace(/\/$/, ''),
|
|
||||||
origin: this.site.replace(/\/$/, ''),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
).then(res => res.json()),
|
).then(res => res.json()),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
@@ -359,16 +139,9 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
path: novelPath,
|
path: novelPath,
|
||||||
name:
|
name: loadedCheerio('h1.novel-title').text() || 'Untitled',
|
||||||
loadedCheerio(
|
cover: loadedCheerio('img.novel-image').attr('src'),
|
||||||
'.novelpaewrapper div.image-container.w-embed > img',
|
summary: loadedCheerio('div.synopsis.w-richtext').text().trim(),
|
||||||
).attr('alt') || 'Untitled',
|
|
||||||
cover: loadedCheerio(
|
|
||||||
'.novelpaewrapper div.image-container.w-embed > img',
|
|
||||||
).attr('src'),
|
|
||||||
summary: loadedCheerio('.novelpaewrapper div.synopsis.w-richtext')
|
|
||||||
.text()
|
|
||||||
.trim(),
|
|
||||||
chapters: posts
|
chapters: posts
|
||||||
.map(chap => ({
|
.map(chap => ({
|
||||||
name: chap.acf.ch_name,
|
name: chap.acf.ch_name,
|
||||||
@@ -378,13 +151,18 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
chapterNumber: chap.acf.chapter_number,
|
chapterNumber: chap.acf.chapter_number,
|
||||||
}))
|
}))
|
||||||
.reverse(),
|
.reverse(),
|
||||||
status: loadedCheerio(
|
status: loadedCheerio('.novelstatustextlarge').text(),
|
||||||
'.novelpaewrapper div.novelstatustextmedium',
|
author: loadedCheerio(
|
||||||
).text(),
|
'div.additionalinfo.tm10 > div.textwrapper:nth-child(1)',
|
||||||
author: loadedCheerio('.novelpaewrapper div.mobileauthorname').text(),
|
|
||||||
genres: loadedCheerio(
|
|
||||||
'.novelpaewrapper div.novelgenre.mobile > div > div > a > div',
|
|
||||||
)
|
)
|
||||||
|
.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())
|
.map((i, el) => loadedCheerio(el).text())
|
||||||
.toArray()
|
.toArray()
|
||||||
.join(','),
|
.join(','),
|
||||||
@@ -436,31 +214,23 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadAll() {
|
async loadAll() {
|
||||||
let pageQueryId;
|
const data = await fetchApi(
|
||||||
let pageCount = 1;
|
this._chapSite + 'wp-json/wp/v2/mvl-novels?per_page=10000',
|
||||||
const pages = [
|
).then(r => r.json());
|
||||||
...(await this.parseNovelListPage(
|
// @ts-ignore
|
||||||
`${this.site}advance-search`,
|
return data.map(novel => {
|
||||||
(a, b) => {
|
return {
|
||||||
pageQueryId = a.split('_page=')[0];
|
name: novel.name,
|
||||||
pageCount = b;
|
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'],
|
||||||
const followingPages = [];
|
created: new Date(novel['created']).getTime(),
|
||||||
for (let i = 2; i <= pageCount; i++) {
|
genres: novel.genre,
|
||||||
followingPages.push(
|
tags: novel.tags,
|
||||||
this.parseNovelListPage(
|
};
|
||||||
`${this.site}advance-search${pageQueryId}_page=${i}`,
|
});
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const pagesAwaited = await Promise.all(followingPages);
|
|
||||||
pagesAwaited.forEach(page => pages.push(...page));
|
|
||||||
|
|
||||||
return pages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filters = {
|
filters = {
|
||||||
@@ -470,7 +240,6 @@ class MVLEMPYRPlugin implements Plugin.PluginBase {
|
|||||||
label: 'Order by',
|
label: 'Order by',
|
||||||
options: [
|
options: [
|
||||||
{ label: 'Latest Added', value: 'created' },
|
{ label: 'Latest Added', value: 'created' },
|
||||||
{ label: 'Latest Updated', value: 'updated' },
|
|
||||||
{ label: 'Best Rated', value: 'avgReview' },
|
{ label: 'Best Rated', value: 'avgReview' },
|
||||||
{ label: 'Most Reviewed', value: 'reviewCount' },
|
{ label: 'Most Reviewed', value: 'reviewCount' },
|
||||||
{ label: 'Chapter Count', value: 'chapterCount' },
|
{ label: 'Chapter Count', value: 'chapterCount' },
|
||||||
@@ -1468,7 +1237,6 @@ type ExtraNovelData = {
|
|||||||
avgReview: number;
|
avgReview: number;
|
||||||
reviewCount: number;
|
reviewCount: number;
|
||||||
chapterCount: number;
|
chapterCount: number;
|
||||||
updated: number;
|
|
||||||
created: number;
|
created: number;
|
||||||
genres: string[];
|
genres: string[];
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
|||||||
Reference in New Issue
Block a user