Add TopLiba (#1003)
* test * cleanup deleted unused `fetchFile` import replaced fetch with `fetchApi` * eslint * fix * fix multi * Hmm, what to do next. * test URLSearchParams * fix
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import qs from 'qs';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import qs from 'qs';
|
||||
@@ -48,7 +48,7 @@ class NovelsOnline implements Plugin.PluginBase {
|
||||
const result = await fetchApi(this.site + novelPath).then(res =>
|
||||
res.text(),
|
||||
);
|
||||
let $ = parseHTML(result);
|
||||
const $ = parseHTML(result);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelPath,
|
||||
@@ -58,8 +58,8 @@ class NovelsOnline implements Plugin.PluginBase {
|
||||
};
|
||||
|
||||
$('.novel-detail-item').each((i, el) => {
|
||||
let detailName = $(el).find('h6').text();
|
||||
let detail = $(el).find('.novel-detail-body');
|
||||
const detailName = $(el).find('h6').text();
|
||||
const detail = $(el).find('.novel-detail-body');
|
||||
|
||||
switch (detailName) {
|
||||
case 'Description':
|
||||
@@ -111,11 +111,8 @@ class NovelsOnline implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
const result = await fetchApi('https://novelsonline.net/sResults.php', {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const result = await fetchApi(this.site + '/sResults.php', {
|
||||
headers: {
|
||||
Accept: '*/*',
|
||||
'Accept-Language': 'pl,en-US;q=0.7,en;q=0.3',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
|
||||
@@ -8,54 +8,49 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
name = 'StorySeedling';
|
||||
icon = 'src/en/storyseedling/icon.png';
|
||||
site = 'https://storyseedling.com/';
|
||||
version = '1.0.1';
|
||||
version = '1.0.2';
|
||||
|
||||
async popularNovels(pageNo: number): Promise<Plugin.NovelItem[]> {
|
||||
let novels: Plugin.NovelItem[] = [];
|
||||
let url = 'https://storyseedling.com/ajax';
|
||||
|
||||
const postUrl = `https://storyseedling.com/browse/`;
|
||||
const body = await fetchApi(postUrl).then(r => r.text());
|
||||
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
const body = await fetchApi(this.site + 'browse').then(r => r.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
var postValue = loadedCheerio('div[ax-load][x-data]')
|
||||
const postValue = loadedCheerio('div[ax-load][x-data]')
|
||||
.attr('x-data')
|
||||
?.replace("browse('", '')
|
||||
.replace("')", '') as string;
|
||||
|
||||
var data = new FormData();
|
||||
const data = new FormData();
|
||||
data.append('search', '');
|
||||
data.append('orderBy', 'recent');
|
||||
data.append('curpage', pageNo.toString());
|
||||
data.append('post', postValue);
|
||||
data.append('action', 'fetch_browse');
|
||||
|
||||
var response = await (
|
||||
await fetchApi(url, { body: data, method: 'POST' })
|
||||
).json();
|
||||
const response: any = await fetchApi(this.site + 'ajax', {
|
||||
body: data,
|
||||
method: 'POST',
|
||||
}).then(res => res.json());
|
||||
|
||||
response.data.posts.forEach((element: any) => {
|
||||
const novel = {
|
||||
response.data.posts.forEach((element: any) =>
|
||||
novels.push({
|
||||
name: element.title,
|
||||
cover: element.thumbnail,
|
||||
path: element.permalink.replace(this.site, ''),
|
||||
};
|
||||
novels.push(novel);
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return novels;
|
||||
}
|
||||
|
||||
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
|
||||
var site = this.site;
|
||||
const site = this.site;
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelPath,
|
||||
name: '',
|
||||
};
|
||||
|
||||
const body = await fetchApi(this.site + novelPath).then(r => r.text());
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
novel.name = loadedCheerio('h1').text().trim();
|
||||
@@ -68,7 +63,8 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
if (!novel.cover) {
|
||||
novel.cover = defaultCover;
|
||||
}
|
||||
let genres: string[] = [];
|
||||
|
||||
const genres: string[] = [];
|
||||
loadedCheerio(
|
||||
'section[x-data="{ tab: location.hash.substr(1) || \'chapters\' }"].relative > div > div > div.flex.flex-wrap > a',
|
||||
).each(function () {
|
||||
@@ -81,7 +77,7 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
.trim()
|
||||
.replace(/(\r\n|\n|\r)/gm, '');
|
||||
|
||||
let chapters: Plugin.ChapterItem[] = [];
|
||||
const chapters: Plugin.ChapterItem[] = [];
|
||||
|
||||
loadedCheerio(
|
||||
'div.grid.w-full.grid-cols-1.gap-4.md\\:grid-cols-2 > a',
|
||||
@@ -89,20 +85,20 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
if (loadedCheerio(this).find('> div').length == 2) {
|
||||
return;
|
||||
}
|
||||
let name = loadedCheerio(this).find('.truncate').text().trim();
|
||||
let url = loadedCheerio(this).attr('href') as string;
|
||||
let releaseTime = loadedCheerio(this)
|
||||
const name = loadedCheerio(this).find('.truncate').text().trim();
|
||||
const url = loadedCheerio(this).attr('href') as string;
|
||||
const releaseTime = loadedCheerio(this)
|
||||
.find('div > div > small')
|
||||
.text()
|
||||
.trim();
|
||||
let chapterNumber = name.split('-')[0].trim().split(' ')[1];
|
||||
const chapter: Plugin.ChapterItem = {
|
||||
const chapterNumber = name.split('-')[0].trim().split(' ')[1];
|
||||
|
||||
chapters.push({
|
||||
name: name,
|
||||
path: url.replace(site, ''),
|
||||
releaseTime: releaseTime,
|
||||
releaseTime,
|
||||
chapterNumber: parseInt(chapterNumber),
|
||||
};
|
||||
chapters.push(chapter);
|
||||
});
|
||||
});
|
||||
novel.chapters = chapters;
|
||||
return novel;
|
||||
@@ -111,8 +107,8 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
const body = await fetchApi(this.site + chapterPath).then(r => r.text());
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
let t = loadedCheerio('div.justify-center > div.mb-4');
|
||||
let chapterText = t.html() || '';
|
||||
const t = loadedCheerio('div.justify-center > div.mb-4');
|
||||
const chapterText = t.html() || '';
|
||||
|
||||
return chapterText;
|
||||
}
|
||||
@@ -121,38 +117,35 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let novels: Plugin.NovelItem[] = [];
|
||||
let url = 'https://storyseedling.com/ajax';
|
||||
|
||||
const postUrl = `https://storyseedling.com/browse/`;
|
||||
const body = await fetchApi(postUrl).then(r => r.text());
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
const body = await fetchApi(this.site + 'browse').then(r => r.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
var postValue = loadedCheerio('div[ax-load][x-data]')
|
||||
const postValue = loadedCheerio('div[ax-load][x-data]')
|
||||
.attr('x-data')
|
||||
?.replace("browse('", '')
|
||||
.replace("')", '') as string;
|
||||
|
||||
var data = new FormData();
|
||||
const data = new FormData();
|
||||
data.append('search', searchTerm);
|
||||
data.append('orderBy', 'recent');
|
||||
data.append('curpage', pageNo.toString());
|
||||
data.append('post', postValue);
|
||||
data.append('action', 'fetch_browse');
|
||||
|
||||
var response = await (
|
||||
await fetchApi(url, { body: data, method: 'POST' })
|
||||
).json();
|
||||
const response: any = await fetchApi(this.site + 'ajax', {
|
||||
body: data,
|
||||
method: 'POST',
|
||||
}).then(res => res.json());
|
||||
|
||||
response.data.posts.forEach((element: any) => {
|
||||
const novel = {
|
||||
response.data.posts.forEach((element: any) =>
|
||||
novels.push({
|
||||
name: element.title,
|
||||
cover: element.thumbnail,
|
||||
path: element.permalink.replace(this.site, ''),
|
||||
};
|
||||
novels.push(novel);
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
return novels;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
import { fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
|
||||
@@ -48,7 +48,7 @@ class BLN implements Plugin.PluginBase {
|
||||
link += '&state=' + filters.status.value;
|
||||
link += '&page=' + page;
|
||||
|
||||
const result = await fetch(link);
|
||||
const result = await fetchApi(link);
|
||||
if (!result.ok) {
|
||||
console.error(await result.text());
|
||||
// TODO: Cloudflare protection or other error
|
||||
@@ -61,7 +61,7 @@ class BLN implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
|
||||
const result = await fetch(this.site + novelPath);
|
||||
const result = await fetchApi(this.site + novelPath);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
@@ -146,7 +146,7 @@ class BLN implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const result = await fetch(this.site + chapterPath);
|
||||
const result = await fetchApi(this.site + chapterPath);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
@@ -162,7 +162,7 @@ class BLN implements Plugin.PluginBase {
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}search_novels/${searchTerm}?page=${page}`;
|
||||
|
||||
const result = await fetch(url);
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -52,7 +52,7 @@ class ComradeMaoPlugin implements Plugin.PluginBase {
|
||||
async parseNovelAndChapters(novelUrl: string): Promise<Plugin.SourceNovel> {
|
||||
const body = await fetchApi(novelUrl).then(result => result.text());
|
||||
|
||||
let loadedCheerio = parseHTML(body);
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
url: novelUrl,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
|
||||
@@ -9,7 +9,6 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
site = 'https://www.divinedaolibrary.com/';
|
||||
version = '1.0.1';
|
||||
icon = 'src/en/divinedaolibrary/icon.png';
|
||||
filters?: undefined;
|
||||
|
||||
parseNovels(loadedCheerio: CheerioAPI, searchTerm?: string) {
|
||||
let novels: Plugin.NovelItem[] = [];
|
||||
@@ -40,11 +39,8 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
options: Plugin.PopularNovelsOptions,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let link = this.site + 'novels';
|
||||
async popularNovels(): Promise<Plugin.NovelItem[]> {
|
||||
const link = this.site + 'novels';
|
||||
|
||||
const body = await fetchApi(link).then(res => res.text());
|
||||
|
||||
@@ -56,7 +52,7 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
const result = await fetchApi(this.site + novelPath);
|
||||
const body = await result.text();
|
||||
|
||||
let loadedCheerio = parseHTML(body);
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelPath,
|
||||
@@ -116,11 +112,8 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let url = this.site + 'novels';
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = this.site + 'novels';
|
||||
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
|
||||
@@ -68,7 +68,7 @@ class EarlyNovelPlugin implements Plugin.PagePlugin {
|
||||
const result = await fetchApi(this.site + novelPath);
|
||||
const body = await result.text();
|
||||
|
||||
let loadedCheerio = parseHTML(body);
|
||||
const loadedCheerio = parseHTML(body);
|
||||
loadedCheerio('.glyphicon-menu-right').closest('li').remove();
|
||||
const pagenav = loadedCheerio('.page-nav').prev().find('a');
|
||||
const lastPageStr = pagenav.attr('title')?.match(/(\d+)/);
|
||||
@@ -84,8 +84,8 @@ class EarlyNovelPlugin implements Plugin.PagePlugin {
|
||||
};
|
||||
|
||||
loadedCheerio('.info > div > h3').each(function () {
|
||||
let detailName = loadedCheerio(this).text();
|
||||
let detail = loadedCheerio(this)
|
||||
const detailName = loadedCheerio(this).text();
|
||||
const detail = loadedCheerio(this)
|
||||
.siblings()
|
||||
.map((i, el) => loadedCheerio(el).text())
|
||||
.toArray()
|
||||
@@ -127,10 +127,7 @@ class EarlyNovelPlugin implements Plugin.PagePlugin {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}search?keyword=${searchTerm}`;
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
|
||||
@@ -43,10 +43,7 @@ class FaqWikiUs implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
page: number,
|
||||
{ showLatestNovels }: Plugin.PopularNovelsOptions,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async popularNovels(): Promise<Plugin.NovelItem[]> {
|
||||
const body = await fetchApi(this.site).then(res => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
@@ -79,7 +76,7 @@ class FaqWikiUs implements Plugin.PluginBase {
|
||||
|
||||
const div = loadedCheerio('.book-review-block__meta-item-value');
|
||||
|
||||
div.html(div.html()?.replace(/(?<=>)([^<]+)(?=<br\s*\/?>)/g, '<p>$1</p>')!);
|
||||
div.html(div.html()?.replace(/(?<=>)([^<]+)(?=<br\s*\/?>)/g, '<p>$1</p>'));
|
||||
|
||||
loadedCheerio('.book-review-block__meta-item-value strong').each(
|
||||
(i, el) => {
|
||||
|
||||
@@ -264,8 +264,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
resolveUrl = (path: string, isNovel?: boolean) =>
|
||||
this.site + '/novel/' + path;
|
||||
resolveUrl = (path: string) => this.site + '/novel/' + path;
|
||||
|
||||
filters = {
|
||||
order: {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import qs from 'qs';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Parser } from 'htmlparser2';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -85,7 +85,7 @@ class LightNovelPub implements Plugin.PagePlugin {
|
||||
let isSummary = false;
|
||||
let isGenres = false;
|
||||
let isTags = false;
|
||||
let genreArray: string[] = [];
|
||||
const genreArray: string[] = [];
|
||||
let isCover = false;
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
@@ -245,7 +245,7 @@ class LightNovelPub implements Plugin.PagePlugin {
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
if (isChapter && name === 'div') {
|
||||
let stylediv = attribs['style'];
|
||||
const stylediv = attribs['style'];
|
||||
if (stylediv) {
|
||||
chapterText += `<div style="${stylediv}">`;
|
||||
isStyleText = true;
|
||||
@@ -254,7 +254,7 @@ class LightNovelPub implements Plugin.PagePlugin {
|
||||
}
|
||||
}
|
||||
if (isChapter && name === 'table') {
|
||||
let w = attribs['width'];
|
||||
const w = attribs['width'];
|
||||
if (w) {
|
||||
chapterText += `<table width="${w}">`;
|
||||
} else {
|
||||
@@ -268,7 +268,7 @@ class LightNovelPub implements Plugin.PagePlugin {
|
||||
chapterText += `<tr>`;
|
||||
}
|
||||
if (isChapter && name === 'td') {
|
||||
let w1 = attribs['width'];
|
||||
const w1 = attribs['width'];
|
||||
if (w1) {
|
||||
chapterText += `<td width="${w1}">`;
|
||||
} else {
|
||||
@@ -334,10 +334,7 @@ class LightNovelPub implements Plugin.PagePlugin {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}lnsearchlive`;
|
||||
const link = `${this.site}search`;
|
||||
const response = await fetchApi(link).then(r => r.text());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Parser } from 'htmlparser2';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
|
||||
@@ -87,7 +87,7 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
let isStatusKey = false;
|
||||
let isList = 0;
|
||||
let isGenres = false;
|
||||
let genreArray: string[] = [];
|
||||
const genreArray: string[] = [];
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
if (name === 'img' && attribs['class']?.includes('img-rounded')) {
|
||||
@@ -272,10 +272,7 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
return chapterText.replace(/„/g, '“');
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const html = await fetchApi(this.site)
|
||||
.then(b => b.text())
|
||||
.then(r => r.replace(/>\s+</g, '><'));
|
||||
@@ -312,7 +309,7 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
parser.write(html);
|
||||
parser.end();
|
||||
|
||||
const search = await fetch(`${this.site}${list}`);
|
||||
const search = await fetchApi(`${this.site}${list}`);
|
||||
const data = await search.json();
|
||||
|
||||
const nov = data.filter((res: { name: string }) =>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
@@ -21,7 +21,9 @@ class MTLNovel implements Plugin.PluginBase {
|
||||
|
||||
const headers = new Headers();
|
||||
headers.append('Alt-Used', 'www.mtlnovel.com');
|
||||
const body = await fetch(link, { headers }).then(result => result.text());
|
||||
const body = await fetchApi(link, { headers }).then(result =>
|
||||
result.text(),
|
||||
);
|
||||
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
@@ -50,7 +52,7 @@ class MTLNovel implements Plugin.PluginBase {
|
||||
headers.append('Referer', `${this.site}novel-list/`);
|
||||
headers.append('Alt-Used', 'www.mtlnovel.com');
|
||||
|
||||
const body = await fetch(this.site + novelPath, {
|
||||
const body = await fetchApi(this.site + novelPath, {
|
||||
headers,
|
||||
}).then(result => result.text());
|
||||
|
||||
@@ -70,7 +72,7 @@ class MTLNovel implements Plugin.PluginBase {
|
||||
const chapterListUrl = this.site + novelPath + 'chapter-list/';
|
||||
|
||||
const getChapters = async () => {
|
||||
const listResult = await fetch(chapterListUrl, { headers });
|
||||
const listResult = await fetchApi(chapterListUrl, { headers });
|
||||
const listBody = await listResult.text();
|
||||
|
||||
loadedCheerio = parseHTML(listBody);
|
||||
@@ -101,7 +103,7 @@ class MTLNovel implements Plugin.PluginBase {
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const headers = new Headers();
|
||||
headers.append('Alt-Used', 'www.mtlnovel.com');
|
||||
const body = await fetch(this.site + chapterPath, { headers }).then(r =>
|
||||
const body = await fetchApi(this.site + chapterPath, { headers }).then(r =>
|
||||
r.text(),
|
||||
);
|
||||
|
||||
@@ -112,19 +114,13 @@ class MTLNovel implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const headers = new Headers();
|
||||
headers.append('Alt-Used', 'www.mtlnovel.com');
|
||||
const searchUrl =
|
||||
this.site +
|
||||
'wp-admin/admin-ajax.php?action=autosuggest&q=' +
|
||||
searchTerm +
|
||||
'&__amp_source_origin=https%3A%2F%2Fwww.mtlnovel.com';
|
||||
this.site + 'wp-admin/admin-ajax.php?action=autosuggest&q=' + searchTerm;
|
||||
|
||||
const res = await fetch(searchUrl, { headers });
|
||||
const res = await fetchApi(searchUrl, { headers });
|
||||
const result = await res.json();
|
||||
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters } from '@libs/filterInputs';
|
||||
|
||||
class MTLReader implements Plugin.PluginBase {
|
||||
id = 'mtlreader';
|
||||
@@ -9,6 +8,7 @@ class MTLReader implements Plugin.PluginBase {
|
||||
version = '1.0.0';
|
||||
icon = 'src/en/mtlreader/icon.png';
|
||||
site = 'https://mtlreader.com/';
|
||||
|
||||
parseNovels(loadedCheerio: CheerioAPI) {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
@@ -31,10 +31,7 @@ class MTLReader implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
options: Plugin.PopularNovelsOptions<Filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async popularNovels(pageNo: number): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}novels?page=${pageNo}`;
|
||||
|
||||
const body = await fetchApi(url).then(r => r.text());
|
||||
@@ -90,10 +87,7 @@ class MTLReader implements Plugin.PluginBase {
|
||||
|
||||
return chapterText;
|
||||
}
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const body = await fetchApi(this.site).then(r => r.text());
|
||||
const tokenCheerio = parseHTML(body);
|
||||
const token = tokenCheerio('input[name="_token"]').attr('value');
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
@@ -73,8 +73,8 @@ class NovelBin implements Plugin.PluginBase {
|
||||
};
|
||||
|
||||
loadedCheerio('ul.info > li > h3').each(function () {
|
||||
let detailName = loadedCheerio(this).text();
|
||||
let detail = loadedCheerio(this)
|
||||
const detailName = loadedCheerio(this).text();
|
||||
const detail = loadedCheerio(this)
|
||||
.siblings()
|
||||
.map((i, el) => loadedCheerio(el).text())
|
||||
.toArray()
|
||||
@@ -137,10 +137,7 @@ class NovelBin implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}search/?keyword=${searchTerm}`;
|
||||
const body = await fetchApi(url).then(r => r.text());
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters } from '@libs/filterInputs';
|
||||
|
||||
class NovelBuddy implements Plugin.PluginBase {
|
||||
id = 'novelbuddy';
|
||||
@@ -9,7 +8,6 @@ class NovelBuddy implements Plugin.PluginBase {
|
||||
site = 'https://novelbuddy.io/';
|
||||
version = '1.0.0';
|
||||
icon = 'src/en/novelbuddy/icon.png';
|
||||
filters?: undefined; //TODO: Filters, Filters in Filters required
|
||||
|
||||
parseNovels(loadedCheerio: CheerioAPI) {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
@@ -33,10 +31,7 @@ class NovelBuddy implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
options: Plugin.PopularNovelsOptions,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async popularNovels(pageNo: number): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}popular?page=${pageNo}`;
|
||||
|
||||
const result = await fetchApi(url);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { load, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters } from '@libs/filterInputs';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
|
||||
class NovelHall implements Plugin.PluginBase {
|
||||
@@ -9,13 +8,9 @@ class NovelHall implements Plugin.PluginBase {
|
||||
name = 'Novel Hall';
|
||||
version = '1.0.1';
|
||||
icon = 'src/en/novelhall/icon.png';
|
||||
filters?: Filters | undefined; //TODO: Filters Requires hideOnSelect
|
||||
site = 'https://novelhall.com/';
|
||||
|
||||
async popularNovels(
|
||||
page: number,
|
||||
options: Plugin.PopularNovelsOptions<Filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async popularNovels(page: number): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}all2022-${page}.html`;
|
||||
|
||||
const body = await fetchApi(url).then(r => r.text());
|
||||
@@ -94,10 +89,7 @@ class NovelHall implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}index.php?s=so&module=book&keyword=${searchTerm}`;
|
||||
const body = await fetchApi(url).then(r => r.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
@@ -142,7 +143,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
|
||||
loadedCheerio = parseHTML(text);
|
||||
|
||||
const nameReplacements: { [key: string]: string } = {
|
||||
const nameReplacements: Record<string, string> = {
|
||||
'v': 'volume ',
|
||||
'c': ' chapter ',
|
||||
'part': 'part ',
|
||||
@@ -151,7 +152,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
|
||||
loadedCheerio('li.sp_li_chp').each((i, el) => {
|
||||
let chapterName = loadedCheerio(el).text();
|
||||
for (let name in nameReplacements) {
|
||||
for (const name in nameReplacements) {
|
||||
chapterName = chapterName.replace(name, nameReplacements[name]);
|
||||
}
|
||||
chapterName = chapterName.replace(/\b\w/g, l => l.toUpperCase()).trim();
|
||||
@@ -170,7 +171,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
getLocation(href: string) {
|
||||
var match = href.match(
|
||||
const match = href.match(
|
||||
/^(https?:)\/\/(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/,
|
||||
);
|
||||
return match && `${match[1]}//${match[3]}`;
|
||||
@@ -198,7 +199,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
}
|
||||
break;
|
||||
case 'asuratls':
|
||||
let titleElementAsura = loadedCheerio('.post-body div b').first();
|
||||
const titleElementAsura = loadedCheerio('.post-body div b').first();
|
||||
chapterTitle = titleElementAsura.text()!;
|
||||
titleElementAsura.remove();
|
||||
chapterContent = loadedCheerio('.post-body').html()!;
|
||||
@@ -235,7 +236,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
loadedCheerio('#readerarea.rdminimal')
|
||||
.children()
|
||||
.each((idx, ele) => {
|
||||
let elementText = loadedCheerio(ele).text();
|
||||
const elementText = loadedCheerio(ele).text();
|
||||
if (elementText.includes(chapterStringHelScans)) {
|
||||
chapterTitle = elementText;
|
||||
loadedCheerio(ele).remove();
|
||||
@@ -295,12 +296,12 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
case 'ko-fi':
|
||||
chapterText = loadedCheerio('script:contains("shadowDom.innerHTML")')
|
||||
.html()
|
||||
?.match(/shadowDom\.innerHTML \+= '(<div.*?)';/)![1]!;
|
||||
?.match(/shadowDom\.innerHTML \+= '(<div.*?)';/)![1];
|
||||
break;
|
||||
case 'mirilu':
|
||||
bloatClasses = ['#jp-post-flair'];
|
||||
bloatClasses.map(tag => loadedCheerio(tag).remove());
|
||||
let titleElementMirilu = loadedCheerio(
|
||||
const titleElementMirilu = loadedCheerio(
|
||||
'.entry-content p strong',
|
||||
).first();
|
||||
chapterTitle = titleElementMirilu.text()!;
|
||||
@@ -360,10 +361,10 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
}
|
||||
break;
|
||||
case 'rainofsnow':
|
||||
let displayedDivSnow = loadedCheerio('.bb-item').filter(function () {
|
||||
const displayedDivSnow = loadedCheerio('.bb-item').filter(function () {
|
||||
return loadedCheerio(this).css('display') === 'block';
|
||||
});
|
||||
let loadedCheerioSnow = parseHTML(displayedDivSnow.html()!);
|
||||
const loadedCheerioSnow = parseHTML(displayedDivSnow.html()!);
|
||||
bloatClasses = [
|
||||
'.responsivevoice-button',
|
||||
'.zoomdesc-cont p img',
|
||||
@@ -371,7 +372,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
];
|
||||
bloatClasses.map(tag => loadedCheerioSnow(tag).remove());
|
||||
chapterContent = loadedCheerioSnow('.zoomdesc-cont').html()!;
|
||||
let titleElementSnow = loadedCheerioSnow('.scroller h2').first();
|
||||
const titleElementSnow = loadedCheerioSnow('.scroller h2').first();
|
||||
if (titleElementSnow.length) {
|
||||
chapterTitle = titleElementSnow.text()!;
|
||||
titleElementSnow.remove();
|
||||
@@ -473,7 +474,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
];
|
||||
bloatClasses.map(tag => loadedCheerioSyringe(tag).remove());
|
||||
chapterContent = loadedCheerioSyringe('.entry-content').html()!;
|
||||
let titleElementSyringe =
|
||||
const titleElementSyringe =
|
||||
loadedCheerioSyringe('.entry-content h3').first();
|
||||
if (titleElementSyringe.length) {
|
||||
chapterTitle = titleElementSyringe.text();
|
||||
@@ -535,7 +536,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
bloatClasses = ['hr', 'p:contains("\u00a0")'];
|
||||
bloatClasses.map(tag => loadedCheerio(tag).remove());
|
||||
chapterContent = loadedCheerio('.text-left').html()!;
|
||||
let titleElementZetro = loadedCheerio('.text-left h2').first();
|
||||
const titleElementZetro = loadedCheerio('.text-left h2').first();
|
||||
if (titleElementZetro.length) {
|
||||
chapterTitle = titleElementZetro.text()!;
|
||||
titleElementZetro.remove();
|
||||
@@ -590,7 +591,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
/**
|
||||
* Detect if the site is a Blogspot site
|
||||
*/
|
||||
let isBlogspotStr =
|
||||
const isBlogspotStr =
|
||||
loadedCheerio('meta[name="google-adsense-platform-domain"]').attr(
|
||||
'content',
|
||||
) || loadedCheerio('meta[name="generator"]').attr('content');
|
||||
@@ -604,7 +605,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
/**
|
||||
* Detect if the site is a WordPress site
|
||||
*/
|
||||
let isWordPressStr =
|
||||
const isWordPressStr =
|
||||
loadedCheerio('#dcl_comments-js-extra').html() ||
|
||||
loadedCheerio('meta[name="generator"]').attr('content') ||
|
||||
loadedCheerio('footer').text()!;
|
||||
@@ -726,7 +727,7 @@ class NovelUpdates implements Plugin.PluginBase {
|
||||
loadedCheerio('.title_story').first().text() ||
|
||||
loadedCheerio('.active').first().text() ||
|
||||
loadedCheerio('head title').first().text()!;
|
||||
let chapterSubtitle = loadedCheerio('.cat-series').first().text() || '';
|
||||
const chapterSubtitle = loadedCheerio('.cat-series').first().text() || '';
|
||||
if (chapterSubtitle) {
|
||||
chapterTitle = chapterSubtitle;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Parser } from 'htmlparser2';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
|
||||
class RanobesPlugin implements Plugin.PagePlugin {
|
||||
@@ -8,7 +7,6 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
name = 'Ranobes';
|
||||
icon = 'src/en/ranobes/icon.png';
|
||||
site = 'https://ranobes.top';
|
||||
filters?: Filters | undefined;
|
||||
version = '2.0.0';
|
||||
|
||||
async sleep(ms: number) {
|
||||
@@ -81,14 +79,8 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
return chapter.reverse();
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
page: number,
|
||||
{
|
||||
showLatestNovels,
|
||||
filters,
|
||||
}: Plugin.PopularNovelsOptions<typeof this.filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let link = `${this.site}/novels/page/${page}/`;
|
||||
async popularNovels(page: number): Promise<Plugin.NovelItem[]> {
|
||||
const link = `${this.site}/novels/page/${page}/`;
|
||||
const body = await fetchApi(link).then(r => r.text());
|
||||
|
||||
return this.parseNovels(body);
|
||||
@@ -107,7 +99,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
chapters: [],
|
||||
totalPages: 1,
|
||||
};
|
||||
let baseUrl = this.site;
|
||||
const baseUrl = this.site;
|
||||
let isCover = false;
|
||||
let isAuthor = false;
|
||||
let isSummary = false;
|
||||
@@ -115,7 +107,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
let isStatusText = false;
|
||||
let isGenres = false;
|
||||
let isGenresText = false;
|
||||
let genreArray: string[] = [];
|
||||
const genreArray: string[] = [];
|
||||
let novelId = '';
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
@@ -276,7 +268,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
if (isChapter && name === 'div') {
|
||||
let stylediv = attribs['style'];
|
||||
const stylediv = attribs['style'];
|
||||
if (stylediv) {
|
||||
chapterText += `<div style="${stylediv}">`;
|
||||
isStyleText = true;
|
||||
@@ -285,7 +277,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
}
|
||||
}
|
||||
if (isChapter && name === 'table') {
|
||||
let w = attribs['width'];
|
||||
const w = attribs['width'];
|
||||
if (w) {
|
||||
chapterText += `<table width="${w}">`;
|
||||
} else {
|
||||
@@ -299,7 +291,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
chapterText += `<tr>`;
|
||||
}
|
||||
if (isChapter && name === 'td') {
|
||||
let w1 = attribs['width'];
|
||||
const w1 = attribs['width'];
|
||||
if (w1) {
|
||||
chapterText += `<td width="${w1}">`;
|
||||
} else {
|
||||
@@ -369,7 +361,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
|
||||
searchTerm: string,
|
||||
page: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let link = `${this.site}/search/${searchTerm}/page/${page}`;
|
||||
const link = `${this.site}/search/${searchTerm}/page/${page}`;
|
||||
const body = await fetchApi(link).then(r => r.text());
|
||||
|
||||
return this.parseNovels(body);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { isUrlAbsolute } from '@libs/isAbsoluteUrl';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -152,10 +152,7 @@ class ReadLiteNovel implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url =
|
||||
this.site + `/search/autocomplete?dataType=json&query=${searchTerm}`;
|
||||
const result = await fetchApi(url);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { fetchFile, fetchText } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters } from '@libs/filterInputs';
|
||||
import { load as loadCheerio, CheerioAPI } from 'cheerio';
|
||||
import { load as loadCheerio } from 'cheerio';
|
||||
import { defaultCover } from '@libs/defaultCover';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
import { NovelItem } from '../../test_web/static/js';
|
||||
// import { isUrlAbsolute } from "@libs/isAbsoluteUrl";
|
||||
// import { parseMadaraDate } from "@libs/parseMadaraDate";
|
||||
|
||||
interface FuzzySearchOptions {
|
||||
caseSensitive: boolean;
|
||||
@@ -69,8 +67,8 @@ class FuzzySearch<Item> {
|
||||
}
|
||||
const results: { item: Item; score: number }[] = [];
|
||||
|
||||
for (let item of this.haystack) {
|
||||
for (let value of this.getItems(item)) {
|
||||
for (const item of this.haystack) {
|
||||
for (const value of this.getItems(item)) {
|
||||
const score = this.isMatch(value, query);
|
||||
if (score !== undefined) {
|
||||
results.push({ item, score });
|
||||
@@ -112,11 +110,11 @@ class FuzzySearch<Item> {
|
||||
|
||||
nearestIndexesFor(item: string, query: string): number[] | undefined {
|
||||
const letters = query.split('');
|
||||
let indexes: number[][] = [];
|
||||
const indexes: number[][] = [];
|
||||
|
||||
const idxFL = this.idxFirstLetter(item, query);
|
||||
|
||||
for (let idx of idxFL) {
|
||||
for (const idx of idxFL) {
|
||||
indexes.push([idx]);
|
||||
for (let i = 1; i < letters.length; i++) {
|
||||
const letter = letters[i];
|
||||
@@ -139,8 +137,8 @@ class FuzzySearch<Item> {
|
||||
return a[0] - b[0];
|
||||
}
|
||||
|
||||
let res_a = a[a.length - 1] - a[0];
|
||||
let res_b = b[b.length - 1] - b[0];
|
||||
const res_a = a[a.length - 1] - a[0];
|
||||
const res_b = b[b.length - 1] - b[0];
|
||||
|
||||
return res_a - res_b;
|
||||
})[0];
|
||||
@@ -167,21 +165,20 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
icon = 'src/en/relibrary/icon.png';
|
||||
site = 'https://re-library.com';
|
||||
version = '1.0.0';
|
||||
filters: Filters | undefined = undefined;
|
||||
|
||||
private searchFunc: FuzzySearch<Plugin.NovelItem> = new FuzzySearch(
|
||||
item => [item.name],
|
||||
{ sort: true, caseSensitive: false },
|
||||
);
|
||||
private searchFunc = new FuzzySearch<Plugin.NovelItem>(item => [item.name], {
|
||||
sort: true,
|
||||
caseSensitive: false,
|
||||
});
|
||||
|
||||
private async popularNovelsInner(url: string): Promise<Plugin.NovelItem[]> {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
const result = await fetch(url);
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = loadCheerio(body);
|
||||
loadedCheerio('.entry-content > ol > li').each((_i, el) => {
|
||||
let novel: Partial<NovelItem> = {};
|
||||
const novel: Partial<NovelItem> = {};
|
||||
novel.name = loadedCheerio(el).find('h3 > a').text();
|
||||
novel.path = loadedCheerio(el)
|
||||
.find('table > tbody > tr > td > a')
|
||||
@@ -201,12 +198,12 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
|
||||
private async lastestNovelsInner(url: string): Promise<Plugin.NovelItem[]> {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
const result = await fetch(url);
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = loadCheerio(body);
|
||||
loadedCheerio('article.type-page.page').each((_i, el) => {
|
||||
let novel: Partial<Plugin.NovelItem> = {};
|
||||
const novel: Partial<Plugin.NovelItem> = {};
|
||||
novel.name = loadedCheerio(el).find('.entry-title').text();
|
||||
novel.path = loadedCheerio(el).find('.entry-title a').attr('href');
|
||||
if (novel.path === undefined || novel.name === undefined) return;
|
||||
@@ -224,10 +221,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
{
|
||||
showLatestNovels,
|
||||
filters,
|
||||
}: Plugin.PopularNovelsOptions<typeof this.filters>,
|
||||
{ showLatestNovels }: Plugin.PopularNovelsOptions<Filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
// The most-popular page only has a single page, so we return an empty array in case you ask for the impossible
|
||||
// the lastest page do have paginated result, so we support that.
|
||||
@@ -241,7 +235,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
|
||||
let novel: Partial<Plugin.SourceNovel> = {
|
||||
const novel: Partial<Plugin.SourceNovel> = {
|
||||
path: novelPath,
|
||||
};
|
||||
// title: .entry-content > header.entry-header > .entry-title
|
||||
@@ -250,7 +244,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
// synopis: .entry-content > div.su-box > div.su-box-content
|
||||
// chapters: .entry-content > div.su-accordion <then> li.page_item[]
|
||||
|
||||
const result = await fetch(`${this.site}/${novelPath}`);
|
||||
const result = await fetchApi(`${this.site}/${novelPath}`);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = loadCheerio(body);
|
||||
@@ -271,7 +265,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
|
||||
// Genres in comma separated "list"
|
||||
novel.genres = (() => {
|
||||
let genres: string[] = [];
|
||||
const genres: string[] = [];
|
||||
loadedCheerio(
|
||||
'.entry-content > table > tbody > tr > td > p > span > a',
|
||||
).each((_i, el) => {
|
||||
@@ -303,7 +297,7 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
'.entry-content > div.su-box > div.su-box-content',
|
||||
).text();
|
||||
|
||||
let chapters: Plugin.ChapterItem[] = [];
|
||||
const chapters: Plugin.ChapterItem[] = [];
|
||||
|
||||
let chapter_idx = 0;
|
||||
loadedCheerio('.entry-content > div.su-accordion').each((_i1, el) => {
|
||||
@@ -336,16 +330,16 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
// parse chapter text here
|
||||
const result = await fetch(`${this.site}/${chapterPath}`);
|
||||
const result = await fetchApi(`${this.site}/${chapterPath}`);
|
||||
const body = await result.text();
|
||||
|
||||
const loadedCheerio = loadCheerio(body);
|
||||
let text: string[] = [];
|
||||
const text: string[] = [];
|
||||
loadedCheerio('.entry-content > p')
|
||||
.slice(1)
|
||||
.each((_i, el) => {
|
||||
loadedCheerio(el).find('span').remove();
|
||||
let t = loadedCheerio(el).html();
|
||||
const t = loadedCheerio(el).html();
|
||||
if (t === undefined) return;
|
||||
text.push(`<p>${t}</p>`);
|
||||
});
|
||||
@@ -363,14 +357,14 @@ class ReLibraryPlugin implements Plugin.PluginBase {
|
||||
// We only want to serve a single "page" since we do the search client side.
|
||||
if (pageNo !== 1) return [];
|
||||
|
||||
let novels: Plugin.NovelItem[] = [];
|
||||
const req = await fetch(`${this.site}/translations/`);
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
const req = await fetchApi(`${this.site}/translations/`);
|
||||
const body = await req.text();
|
||||
|
||||
const loadedCheerio = loadCheerio(body);
|
||||
|
||||
loadedCheerio('.entry-content table a').each((_i, el) => {
|
||||
let e = loadedCheerio(el);
|
||||
const e = loadedCheerio(el);
|
||||
if (e && e.attr('href') && e.text()) {
|
||||
let path = e.attr('href')!;
|
||||
if (path.startsWith(this.site)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Parser } from 'htmlparser2';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters, FilterTypes } from '@libs/filterInputs';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
@@ -86,7 +86,7 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
let isSpan = 0;
|
||||
let isTags = false;
|
||||
let isGenres = false;
|
||||
let genreArray: string[] = [];
|
||||
const genreArray: string[] = [];
|
||||
let isFooter = false;
|
||||
let isScript = false;
|
||||
let chapterJson: ChapterEntry[] = [];
|
||||
@@ -226,7 +226,7 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
const parser = new Parser({
|
||||
onopentag(name, attribs) {
|
||||
if (isChapter && name === 'div') {
|
||||
let stylediv = attribs['style'];
|
||||
const stylediv = attribs['style'];
|
||||
if (stylediv) {
|
||||
chapterText += `<div style="${stylediv}">`;
|
||||
isStyleText = true;
|
||||
@@ -235,7 +235,7 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
}
|
||||
}
|
||||
if (isChapter && name === 'table') {
|
||||
let w = attribs['width'];
|
||||
const w = attribs['width'];
|
||||
if (w) {
|
||||
chapterText += `<table width="${w}">`;
|
||||
} else {
|
||||
@@ -249,7 +249,7 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
chapterText += `<tr>`;
|
||||
}
|
||||
if (isChapter && name === 'td') {
|
||||
let w1 = attribs['width'];
|
||||
const w1 = attribs['width'];
|
||||
if (w1) {
|
||||
chapterText += `<td width="${w1}">`;
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import dayjs from 'dayjs';
|
||||
@@ -173,10 +173,7 @@ class ScribbleHubPlugin implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = `${this.site}?s=${searchTerm}&post_type=fictionposts`;
|
||||
const result = await fetchApi(url);
|
||||
const body = await result.text();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { fetchApi, fetchFile } from '@libs/fetch';
|
||||
import { fetchApi } from '@libs/fetch';
|
||||
import { FilterTypes, Filters } from '@libs/filterInputs';
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
|
||||
@@ -25,7 +25,7 @@ class WTRLAB implements Plugin.PluginBase {
|
||||
link += `&page=${page}`; //TODO Genre & Advance Searching Filter. Ez to implement, too much manual work, too lazy.
|
||||
|
||||
if (showLatestNovels) {
|
||||
const response = await fetch('https://wtr-lab.com/api/home/recent', {
|
||||
const response = await fetchApi(this.site + 'api/home/recent', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@@ -148,7 +148,7 @@ class WTRLAB implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const response = await fetch(this.site + 'api/search', {
|
||||
const response = await fetchApi(this.site + 'api/search', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Referer: this.site + this.sourceLang,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { load as parseHTML } from 'cheerio';
|
||||
import { fetchApi, fetchFile, fetchProto } from '@libs/fetch';
|
||||
import { fetchApi, fetchProto } from '@libs/fetch';
|
||||
import { Plugin } from '@typings/plugin';
|
||||
import { Filters } from '@libs/filterInputs';
|
||||
import { NovelStatus } from '@libs/novelStatus';
|
||||
@@ -105,6 +105,7 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
name = 'Wuxia World';
|
||||
icon = 'src/en/wuxiaworld/icon.png';
|
||||
site = 'https://www.wuxiaworld.com/';
|
||||
apiSite = 'https://api2.wuxiaworld.com/wuxiaworld.api.v2.';
|
||||
filters?: Filters | undefined;
|
||||
version = '0.5.0';
|
||||
|
||||
@@ -126,10 +127,7 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
return novels;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
options: Plugin.PopularNovelsOptions<Filters>,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
async popularNovels(): Promise<Plugin.NovelItem[]> {
|
||||
const link = `${this.site}api/novels`;
|
||||
|
||||
const result = await fetchApi(link);
|
||||
@@ -146,7 +144,7 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
responseType: 'GetNovelResponse',
|
||||
requestData: { slug: novelPath.split('/')[1] },
|
||||
},
|
||||
'https://api2.wuxiaworld.com/wuxiaworld.api.v2.Novels/GetNovel',
|
||||
this.apiSite + 'Novels/GetNovel',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/grpc-web+proto',
|
||||
@@ -201,7 +199,7 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
responseType: 'GetChapterListResponse',
|
||||
requestData: { novelId: data.item?.id },
|
||||
},
|
||||
'https://api2.wuxiaworld.com/wuxiaworld.api.v2.Chapters/GetChapterList',
|
||||
this.apiSite + 'Chapters/GetChapterList',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/grpc-web+proto',
|
||||
@@ -256,7 +254,7 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
},
|
||||
},
|
||||
},
|
||||
'https://api2.wuxiaworld.com/wuxiaworld.api.v2.Chapters/GetChapter',
|
||||
this.apiSite + 'Chapters/GetChapter',
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/grpc-web+proto',
|
||||
@@ -271,13 +269,8 @@ class WuxiaWorld implements Plugin.PluginBase {
|
||||
return chapterText;
|
||||
}
|
||||
|
||||
async searchNovels(
|
||||
searchTerm: string,
|
||||
pageNo: number,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
const searchUrl = 'https://www.wuxiaworld.com/api/novels/search?query=';
|
||||
|
||||
const url = searchUrl + searchTerm;
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const url = this.site + 'api/novels/search?query=' + searchTerm;
|
||||
|
||||
const result = await fetchApi(url);
|
||||
const data = await result.json();
|
||||
|
||||
Reference in New Issue
Block a user