Feat: ImageRequestInit (#979)

* add ImageRequestInit & fix Hako

* remove multisrc fetchFile

* remove plugins fetchFile

* update docs and template file
This commit is contained in:
nyagami
2024-06-08 20:09:33 +07:00
committed by GitHub
parent 6062f51460
commit 60d95fb8d2
85 changed files with 441 additions and 692 deletions
+21 -38
View File
@@ -29,12 +29,12 @@ class ExamplePlugin implements Plugin.PluginBase {}
| [icon](#pluginbasename) | yes | Plugin Icon | | [icon](#pluginbasename) | yes | Plugin Icon |
| [site](#pluginbasesite) | yes | Plugin site link | | [site](#pluginbasesite) | yes | Plugin site link |
| [version](#pluginbaseversion) | yes | Plugin version | | [version](#pluginbaseversion) | yes | Plugin version |
| [imageRequestInit](#pluginbaseimagerequestinit) | no | Plugin Image Request Init |
| [filters](#pluginbasefilters) | no | [Filter definition](#filter-definition-object) object | | [filters](#pluginbasefilters) | no | [Filter definition](#filter-definition-object) object |
| [popularNovels(page, options)](#pluginbasepopularnovels) | yes | Novel list getter | | [popularNovels(page, options)](#pluginbasepopularnovels) | yes | Novel list getter |
| [parseNovelAndChapters(url)](#pluginbaseparsenovelandchapters) | yes | Novel info and chapter list getter | | [parseNovelAndChapters(url)](#pluginbaseparsenovelandchapters) | yes | Novel info and chapter list getter |
| [parseChapter(url)](#pluginbaseparsechapter) | yes | Chapter text getter | | [parseChapter(url)](#pluginbaseparsechapter) | yes | Chapter text getter |
| [searchNovels(searchTerm, page)](#pluginbasesearchnovels) | yes | Novel searching getter | | [searchNovels(searchTerm, page)](#pluginbasesearchnovels) | yes | Novel searching getter |
| [fetchImage(url)](#pluginbasefetchimage) | yes | Customizable function for fetching images |
#### PluginBase::id #### PluginBase::id
@@ -109,6 +109,26 @@ class ExamplePlugin implements Plugin.PluginBase {
} }
``` ```
#### PluginBase::imageRequestInit
The init for request to obtain images
Used if images failed to load due to site's protection
###### Example
```ts
class ExamplePlugin implements Plugin.PluginBase {
...
imageRequestInit: Plugin.ImageRequestInit = {
headers: {
Referer: 'https://example.com',
},
};
...
}
```
#### PluginBase::filters #### PluginBase::filters
A [Filter definition]() object that holds filters used in [popularNovels](#pluginbasepopularnovels) function A [Filter definition]() object that holds filters used in [popularNovels](#pluginbasepopularnovels) function
@@ -312,43 +332,6 @@ class ExamplePlugin implements Plugin.PluginBase {
} }
``` ```
#### PluginBase::fetchImage
Function used if images failed to load due to site's protection
```ts
async fetchImage(url: string): Promise<string | undefined>
```
See [Fetch functions]() for detailed list of fetch functions provided by us to help with fetching data
###### Parameter
- `url` Image's url to fetch
###### Returns
- `string` base64 representation of the image
or
- `undefined` on error
###### Example
```ts
class ExamplePlugin implements Plugin.PluginBase {
...
async fetchImage(url: string): Promise<string | undefined> {
const headers = {
Referer: "https://ln.hako.vn",
};
return await fetchFile(url, { headers: headers });
}
...
}
```
--- ---
### NovelItem ### NovelItem
+1 -5
View File
@@ -14,6 +14,7 @@ class TemplatePlugin implements Plugin.PluginBase {
site = 'https://example.com'; site = 'https://example.com';
version = '1.0.0'; version = '1.0.0';
filters: Filters | undefined = undefined; filters: Filters | undefined = undefined;
imageRequestInit?: Plugin.ImageRequestInit | undefined = undefined;
async popularNovels( async popularNovels(
pageNo: number, pageNo: number,
@@ -80,11 +81,6 @@ class TemplatePlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new TemplatePlugin(); export default new TemplatePlugin();
-2
View File
@@ -180,8 +180,6 @@ class Shu69 implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
rank: { rank: {
label: '排行榜', label: '排行榜',
-2
View File
@@ -181,8 +181,6 @@ class XinShu69 implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
class: { class: {
label: '分类', label: '分类',
-7
View File
@@ -521,13 +521,6 @@ class Linovelib implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
const headers = new Headers({
'Referer': `${this.site}/`,
});
return await fetchFile(url, { headers });
}
filters = { filters = {
rank: { rank: {
label: '排行榜', label: '排行榜',
-2
View File
@@ -148,8 +148,6 @@ class LibReadPlugin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
fetchImage = fetchFile;
filters = { filters = {
type_genre: { type_genre: {
type: FilterTypes.Picker, type: FilterTypes.Picker,
-4
View File
@@ -146,10 +146,6 @@ class NovelsOnline implements Plugin.PluginBase {
.filter(sr => sr !== null); .filter(sr => sr !== null);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
sort: { sort: {
value: 'top_rated', value: 'top_rated',
-3
View File
@@ -156,9 +156,6 @@ class StorySeedlingPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new StorySeedlingPlugin(); export default new StorySeedlingPlugin();
-4
View File
@@ -148,10 +148,6 @@ class AllNovelFullPlugin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
order: { order: {
value: '/most-popular', value: '/most-popular',
-4
View File
@@ -169,10 +169,6 @@ class BLN implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
status: { status: {
label: 'Status', label: 'Status',
-4
View File
@@ -157,10 +157,6 @@ class ComradeMaoPlugin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
category: { category: {
value: '', value: '',
-4
View File
@@ -128,10 +128,6 @@ class DDLPlugin implements Plugin.PluginBase {
const loadedCheerio = parseHTML(body); const loadedCheerio = parseHTML(body);
return this.parseNovels(loadedCheerio, searchTerm); return this.parseNovels(loadedCheerio, searchTerm);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
} }
export default new DDLPlugin(); export default new DDLPlugin();
-4
View File
@@ -139,10 +139,6 @@ class EarlyNovelPlugin implements Plugin.PagePlugin {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
order: { order: {
value: '/most-popular', value: '/most-popular',
-2
View File
@@ -161,8 +161,6 @@ class FaqWikiUs implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio, searchTerm); return this.parseNovels(loadedCheerio, searchTerm);
} }
fetchImage = fetchFile;
} }
export default new FaqWikiUs(); export default new FaqWikiUs();
-2
View File
@@ -144,8 +144,6 @@ class FreeWebNovel implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
fetchImage = fetchFile;
filters = { filters = {
genres: { genres: {
type: FilterTypes.Picker, type: FilterTypes.Picker,
+110 -108
View File
@@ -19,33 +19,33 @@ class LightNovelPub implements Plugin.PagePlugin {
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
let tempNovel = {} as Plugin.NovelItem; let tempNovel = {} as Plugin.NovelItem;
let isParsingNovel = false; let isParsingNovel = false;
const parser = new Parser ({ const parser = new Parser({
onopentag(name, attribs){ onopentag(name, attribs) {
if (isParsingNovel){ if (isParsingNovel) {
if (name === 'a'){ if (name === 'a') {
tempNovel.path = attribs['href'].slice(1); tempNovel.path = attribs['href'].slice(1);
tempNovel.name = attribs['title']; tempNovel.name = attribs['title'];
} }
if (name === 'img'){ if (name === 'img') {
tempNovel.cover = attribs['data-src'] || attribs['src']; tempNovel.cover = attribs['data-src'] || attribs['src'];
} }
if (tempNovel.path && tempNovel.cover){ if (tempNovel.path && tempNovel.cover) {
novels.push(tempNovel); novels.push(tempNovel);
tempNovel = {} as Plugin.NovelItem; tempNovel = {} as Plugin.NovelItem;
} }
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'class' && value === 'novel-item'){ if (name === 'class' && value === 'novel-item') {
isParsingNovel = true; isParsingNovel = true;
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'li'){ if (name === 'li') {
isParsingNovel = false; isParsingNovel = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
return novels; return novels;
@@ -76,7 +76,7 @@ class LightNovelPub implements Plugin.PagePlugin {
summary: '', summary: '',
totalPages: 1, totalPages: 1,
chapters: [], chapters: [],
} };
let isHeaderStats = false; let isHeaderStats = false;
let isStatus = false; let isStatus = false;
let isTotalChapters = false; let isTotalChapters = false;
@@ -85,95 +85,95 @@ class LightNovelPub implements Plugin.PagePlugin {
let isSummary = false; let isSummary = false;
let isGenres = false; let isGenres = false;
let isTags = false; let isTags = false;
let genreArray: string[] = [] let genreArray: string[] = [];
let isCover = false; let isCover = false;
const parser = new Parser({ const parser = new Parser({
onopentag(name, attribs){ onopentag(name, attribs) {
if(name === 'h1' && attribs['class']?.includes('novel-title')){ if (name === 'h1' && attribs['class']?.includes('novel-title')) {
isNovelName = true; isNovelName = true;
} }
if(name === 'div' && attribs['class']?.includes('content')){ if (name === 'div' && attribs['class']?.includes('content')) {
isSummary = true; isSummary = true;
} }
if(name === 'figure' && attribs['class'] === 'cover'){ if (name === 'figure' && attribs['class'] === 'cover') {
isCover = true; isCover = true;
} }
if(isCover){ if (isCover) {
if(name === 'img'){ if (name === 'img') {
novel.cover = attribs['data-src'] || attribs['src']; novel.cover = attribs['data-src'] || attribs['src'];
} }
} }
}, },
onopentagname(name){ onopentagname(name) {
if (isHeaderStats && name === 'strong'){ if (isHeaderStats && name === 'strong') {
isStatus = true; isStatus = true;
} }
if (isSummary && name === 'br'){ if (isSummary && name === 'br') {
novel.summary += '\n'; novel.summary += '\n';
} }
if (isGenres && name === 'a'){ if (isGenres && name === 'a') {
isTags = true; isTags = true;
} }
}, },
onattribute(name,value){ onattribute(name, value) {
if (name === 'class' && value === 'header-stats'){ if (name === 'class' && value === 'header-stats') {
isTotalChapters = true; isTotalChapters = true;
isHeaderStats = true; isHeaderStats = true;
} }
if (name === 'itemprop' && value === 'author'){ if (name === 'itemprop' && value === 'author') {
isAuthorName = true; isAuthorName = true;
} }
if (name === 'class' && value === 'categories'){ if (name === 'class' && value === 'categories') {
isGenres = true; isGenres = true;
} }
}, },
ontext(data){ ontext(data) {
if(isTotalChapters){ if (isTotalChapters) {
novel.totalPages = Math.ceil(parseInt(data, 10) / 100); novel.totalPages = Math.ceil(parseInt(data, 10) / 100);
} }
if(isStatus){ if (isStatus) {
novel.status = data.trim(); novel.status = data.trim();
} }
if(isNovelName){ if (isNovelName) {
novel.name += data.trim(); novel.name += data.trim();
} }
if(isAuthorName){ if (isAuthorName) {
novel.author = data; novel.author = data;
} }
if(isSummary){ if (isSummary) {
novel.summary += data; novel.summary += data;
} }
if(isTags){ if (isTags) {
genreArray.push(data); genreArray.push(data);
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'strong'){ if (name === 'strong') {
isTotalChapters = false; isTotalChapters = false;
isStatus = false; isStatus = false;
} }
if(name === 'i'){ if (name === 'i') {
isStatus = false; isStatus = false;
} }
if(name === 'h1'){ if (name === 'h1') {
isNovelName = false; isNovelName = false;
} }
if(name === 'span'){ if (name === 'span') {
isAuthorName = false; isAuthorName = false;
} }
if(name === 'div'){ if (name === 'div') {
isHeaderStats = false; isHeaderStats = false;
isSummary = false; isSummary = false;
isGenres = false; isGenres = false;
} }
if(name === 'a'){ if (name === 'a') {
isTags = false; isTags = false;
} }
if(name === 'figure'){ if (name === 'figure') {
isCover = false; isCover = false;
} }
} },
}) });
parser.write(body); parser.write(body);
parser.end(); parser.end();
novel.genres = genreArray.join(', '); novel.genres = genreArray.join(', ');
@@ -184,48 +184,51 @@ class LightNovelPub implements Plugin.PagePlugin {
const url = this.site + novelPath + '/chapters/page-' + page; const url = this.site + novelPath + '/chapters/page-' + page;
const body = await fetchApi(url).then(res => res.text()); const body = await fetchApi(url).then(res => res.text());
const chapter: Plugin.ChapterItem[] = []; const chapter: Plugin.ChapterItem[] = [];
let tempChapter = {} as Plugin.ChapterItem; let tempChapter = {} as Plugin.ChapterItem;
let isChapterItem = false; let isChapterItem = false;
let isChapterList = false; let isChapterList = false;
const parser = new Parser ({ const parser = new Parser({
onopentag(name, attribs){ onopentag(name, attribs) {
if(isChapterList){ if (isChapterList) {
if (name === 'li'){ if (name === 'li') {
isChapterItem = true; isChapterItem = true;
tempChapter.chapterNumber = Number(attribs['data-orderno']); tempChapter.chapterNumber = Number(attribs['data-orderno']);
} }
if (isChapterItem){ if (isChapterItem) {
if (name === 'a'){ if (name === 'a') {
tempChapter.name = attribs['title']; tempChapter.name = attribs['title'];
tempChapter.path = attribs['href'].slice(1); tempChapter.path = attribs['href'].slice(1);
} }
if (name === 'time'){ if (name === 'time') {
tempChapter.releaseTime = dayjs(attribs['datetime']).toISOString(); tempChapter.releaseTime = dayjs(
attribs['datetime'],
).toISOString();
} }
if ( if (
tempChapter.chapterNumber && tempChapter.chapterNumber &&
tempChapter.path && tempChapter.path &&
tempChapter.releaseTime){ tempChapter.releaseTime
chapter.push(tempChapter); ) {
tempChapter = {} as Plugin.ChapterItem; chapter.push(tempChapter);
tempChapter = {} as Plugin.ChapterItem;
} }
} }
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'class' && value === 'chapter-list'){ if (name === 'class' && value === 'chapter-list') {
isChapterList = true; isChapterList = true;
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'a'){ if (name === 'a') {
isChapterItem = false; isChapterItem = false;
} }
if (name === 'ul'){ if (name === 'ul') {
isChapterList = false; isChapterList = false;
} }
} },
}) });
parser.write(body); parser.write(body);
parser.end(); parser.end();
const chapters = chapter; const chapters = chapter;
@@ -240,92 +243,92 @@ class LightNovelPub implements Plugin.PagePlugin {
let isPtag = false; let isPtag = false;
let isStyleText = false; let isStyleText = false;
const parser = new Parser({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
let stylediv = attribs['style'] let stylediv = attribs['style'];
if(stylediv){ if (stylediv) {
chapterText += `<div style="${stylediv}">` chapterText += `<div style="${stylediv}">`;
isStyleText = true; isStyleText = true;
} else { } else {
chapterText += `<div>` chapterText += `<div>`;
} }
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
let w = attribs['width']; let w = attribs['width'];
if(w) { if (w) {
chapterText += `<table width="${w}">`; chapterText += `<table width="${w}">`;
} else { } else {
chapterText += `<table>`; chapterText += `<table>`;
} }
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `<tbody>`; chapterText += `<tbody>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `<tr>`; chapterText += `<tr>`;
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
let w1 = attribs['width']; let w1 = attribs['width'];
if(w1) { if (w1) {
chapterText += `<td width="${w1}">`; chapterText += `<td width="${w1}">`;
} else { } else {
chapterText += `<td>`; chapterText += `<td>`;
} }
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'id' && value === 'chapter-container'){ if (name === 'id' && value === 'chapter-container') {
isChapter = true; isChapter = true;
} }
if (name === 'class' && value?.includes('chapternav')){ if (name === 'class' && value?.includes('chapternav')) {
isChapter = false; isChapter = false;
isPtag = false; isPtag = false;
} }
}, },
onopentagname(name){ onopentagname(name) {
if (isChapter && name === 'p'){ if (isChapter && name === 'p') {
chapterText += '<p>'; chapterText += '<p>';
isPtag = true; isPtag = true;
if(isStyleText){ if (isStyleText) {
isStyleText = false; isStyleText = false;
} }
} }
if (isChapter && name === 'br'){ if (isChapter && name === 'br') {
chapterText += `<br>`; chapterText += `<br>`;
} }
}, },
ontext(data){ ontext(data) {
if(isPtag){ if (isPtag) {
chapterText += data; chapterText += data;
} }
if(isStyleText){ if (isStyleText) {
chapterText += data; chapterText += data;
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'p'){ if (name === 'p') {
isPtag = false; isPtag = false;
chapterText += '</p>' chapterText += '</p>';
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
chapterText += `</td>`; chapterText += `</td>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `</tr>`; chapterText += `</tr>`;
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `</tbody>`; chapterText += `</tbody>`;
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
chapterText += `</table>`; chapterText += `</table>`;
} }
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
isStyleText = false; isStyleText = false;
chapterText += `</div>` chapterText += `</div>`;
} }
} },
}) });
parser.write(body) parser.write(body);
parser.end(); parser.end();
return chapterText; return chapterText;
@@ -339,13 +342,16 @@ class LightNovelPub implements Plugin.PagePlugin {
const link = `${this.site}search`; const link = `${this.site}search`;
const response = await fetchApi(link).then(r => r.text()); const response = await fetchApi(link).then(r => r.text());
let verifytoken = ''; let verifytoken = '';
const parser = new Parser ({ const parser = new Parser({
onopentag(name, attribs) { onopentag(name, attribs) {
if (name === 'input' && attribs['name']?.includes('LNRequestVerifyToken')){ if (
name === 'input' &&
attribs['name']?.includes('LNRequestVerifyToken')
) {
verifytoken = attribs['value']; verifytoken = attribs['value'];
} }
}, },
}) });
parser.write(response); parser.write(response);
parser.end(); parser.end();
@@ -358,11 +364,7 @@ class LightNovelPub implements Plugin.PagePlugin {
body: formData, body: formData,
}).then(r => r.json()); }).then(r => r.json());
return this.parseNovels(body.resultview) return this.parseNovels(body.resultview);
}
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url, { headers: this.headers });
} }
filters = { filters = {
+70 -71
View File
@@ -28,15 +28,15 @@ class LnMTLPlugin implements Plugin.PagePlugin {
const html = await body.text(); const html = await body.text();
const baseUrl = this.site; const baseUrl = this.site;
let isParsingNovel = false; let isParsingNovel = false;
let tempNovel = {} as Plugin.NovelItem; let tempNovel = {} as Plugin.NovelItem;
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
const parser = new Parser ({ const parser = new Parser({
onopentag(name, attribs) { onopentag(name, attribs) {
if (attribs['class']?.includes('media-left')) { if (attribs['class']?.includes('media-left')) {
isParsingNovel = true; isParsingNovel = true;
} }
if (isParsingNovel) { if (isParsingNovel) {
switch (name){ switch (name) {
case 'a': case 'a':
tempNovel.path = attribs['href'].slice(baseUrl.length); tempNovel.path = attribs['href'].slice(baseUrl.length);
break; break;
@@ -45,14 +45,14 @@ class LnMTLPlugin implements Plugin.PagePlugin {
tempNovel.cover = attribs['src']; tempNovel.cover = attribs['src'];
break; break;
} }
if (tempNovel.path && tempNovel.name){ if (tempNovel.path && tempNovel.name) {
novels.push(tempNovel); novels.push(tempNovel);
tempNovel = {} as Plugin.NovelItem; tempNovel = {} as Plugin.NovelItem;
} }
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'div'){ if (name === 'div') {
isParsingNovel = false; isParsingNovel = false;
} }
}, },
@@ -83,59 +83,59 @@ class LnMTLPlugin implements Plugin.PagePlugin {
let isSource = false; let isSource = false;
let isPanelKey = false; let isPanelKey = false;
let isPanelValue = 0; let isPanelValue = 0;
let isAuthorKey = false let isAuthorKey = false;
let isStatusKey = false let isStatusKey = false;
let isList = 0; let isList = 0;
let isGenres = false; let isGenres = false;
let genreArray: string[] = [] let genreArray: string[] = [];
const parser = new Parser({ const parser = new Parser({
onopentag(name,attribs) { onopentag(name, attribs) {
if (name === 'img' && attribs['class']?.includes('img-rounded')){ if (name === 'img' && attribs['class']?.includes('img-rounded')) {
novel.name = attribs['title']; novel.name = attribs['title'];
novel.cover = attribs['src']; novel.cover = attribs['src'];
} }
if (name === 'ul' && attribs['class']?.includes('list-inline')){ if (name === 'ul' && attribs['class']?.includes('list-inline')) {
isList++; isList++;
} }
}, },
onopentagname(name){ onopentagname(name) {
if (name === 'dt'){ if (name === 'dt') {
isPanelKey = true; isPanelKey = true;
} }
if (name === 'dd'){ if (name === 'dd') {
isPanelValue++; isPanelValue++;
} }
if (isList === 1 && name === 'li'){ if (isList === 1 && name === 'li') {
isGenres = true; isGenres = true;
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'class' && value === 'description'){ if (name === 'class' && value === 'description') {
isDescription = true; isDescription = true;
} }
if (name === 'class' && value === 'source'){ if (name === 'class' && value === 'source') {
isDescription = false; isDescription = false;
isSource = true; isSource = true;
} }
if (name === 'class' && value === 'progress'){ if (name === 'class' && value === 'progress') {
isSource = false; isSource = false;
} }
}, },
ontext(data){ ontext(data) {
if(isScript){ if (isScript) {
const volume = JSON.parse( const volume = JSON.parse(
data.match(/lnmtl.volumes = (.+])(?=;)/)![1] || '' data.match(/lnmtl.volumes = (.+])(?=;)/)![1] || '',
); );
novel.totalPages = volume.length; novel.totalPages = volume.length;
} }
if(isDescription){ if (isDescription) {
novel.summary += data.trim() + '\n\n'; novel.summary += data.trim() + '\n\n';
} }
if(isSource){ if (isSource) {
novel.summary += data; novel.summary += data;
} }
if(isPanelKey){ if (isPanelKey) {
switch(data){ switch (data) {
case 'Authors': case 'Authors':
isAuthorKey = true; isAuthorKey = true;
break; break;
@@ -144,32 +144,32 @@ class LnMTLPlugin implements Plugin.PagePlugin {
break; break;
} }
} }
if(isAuthorKey && isPanelValue === 1){ if (isAuthorKey && isPanelValue === 1) {
novel.author += data.trim(); novel.author += data.trim();
isAuthorKey = false; isAuthorKey = false;
} }
if(isStatusKey && isPanelValue === 2){ if (isStatusKey && isPanelValue === 2) {
novel.status += data.trim(); novel.status += data.trim();
isStatusKey = false; isStatusKey = false;
} }
if(isGenres){ if (isGenres) {
genreArray.push(data.trim()); genreArray.push(data.trim());
novel.genres = genreArray.join(', '); novel.genres = genreArray.join(', ');
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'ul'){ if (name === 'ul') {
isGenres = false; isGenres = false;
} }
if(name === 'main'){ if (name === 'main') {
isPanelKey = false; isPanelKey = false;
isScript = true; isScript = true;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
}, },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
return novel; return novel;
@@ -182,25 +182,25 @@ class LnMTLPlugin implements Plugin.PagePlugin {
let volume: VolumeEntry = { let volume: VolumeEntry = {
id: '', id: '',
title: '', title: '',
} };
const parser = new Parser({ const parser = new Parser({
ontext(data){ ontext(data) {
if(isScript){ if (isScript) {
const volumes = JSON.parse( const volumes = JSON.parse(
data.match(/lnmtl.volumes = (.+])(?=;)/)![1] || '' data.match(/lnmtl.volumes = (.+])(?=;)/)![1] || '',
); );
volume = volumes[+page-1] volume = volumes[+page - 1];
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'main'){ if (name === 'main') {
isScript = true; isScript = true;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
}, },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
@@ -243,29 +243,29 @@ class LnMTLPlugin implements Plugin.PagePlugin {
let isText = false; let isText = false;
let chapterText = ''; let chapterText = '';
const parser = new Parser({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if(name === 'sentence' && attribs['class']?.includes('translated')){ if (name === 'sentence' && attribs['class']?.includes('translated')) {
isText = true; isText = true;
chapterText += '<p>' chapterText += '<p>';
} }
}, },
onopentagname(name){ onopentagname(name) {
if(name === 'nav'){ if (name === 'nav') {
isText = false; isText = false;
} }
}, },
ontext(data){ ontext(data) {
if(isText){ if (isText) {
chapterText += data; chapterText += data;
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'sentence'){ if (name === 'sentence') {
chapterText += '</p>' chapterText += '</p>';
isText = false; isText = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
@@ -281,31 +281,34 @@ class LnMTLPlugin implements Plugin.PagePlugin {
.then(r => r.replace(/>\s+</g, '><')); .then(r => r.replace(/>\s+</g, '><'));
let isScript = false; let isScript = false;
let isFooter = false; let isFooter = false;
let list = '' let list = '';
const parser = new Parser({ const parser = new Parser({
onopentag(name, attribs) { onopentag(name, attribs) {
if(isFooter && name === 'script' && if (
attribs['type']?.includes('application/javascript')){ isFooter &&
name === 'script' &&
attribs['type']?.includes('application/javascript')
) {
isScript = true; isScript = true;
} }
}, },
ontext(data){ ontext(data) {
if (isScript){ if (isScript) {
list = data.match(/prefetch: '\/(.*json)/)![1]; list = data.match(/prefetch: '\/(.*json)/)![1];
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'footer'){ if (name === 'footer') {
isFooter = true; isFooter = true;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
if (name === 'body'){ if (name === 'body') {
isFooter = false; isFooter = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
@@ -332,10 +335,6 @@ class LnMTLPlugin implements Plugin.PagePlugin {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
order: { order: {
value: 'favourites', value: 'favourites',
-5
View File
@@ -145,11 +145,6 @@ class MTLNovel implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
const headers = new Headers();
headers.append('Alt-Used', 'www.mtlnovel.com');
return fetchFile(url, { headers });
}
filters = { filters = {
order: { order: {
-4
View File
@@ -103,9 +103,5 @@ class MTLReader implements Plugin.PluginBase {
const loadedCheerio = parseHTML(seacrhBody); const loadedCheerio = parseHTML(seacrhBody);
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new MTLReader(); export default new MTLReader();
+5 -8
View File
@@ -9,6 +9,11 @@ class NovelBin implements Plugin.PluginBase {
icon = 'src/en/novelbin/icon.png'; icon = 'src/en/novelbin/icon.png';
site = 'https://binnovel.com/'; site = 'https://binnovel.com/';
version = '1.0.1'; version = '1.0.1';
imageRequestInit?: Plugin.ImageRequestInit | undefined = {
headers: {
'referrer': this.site,
},
};
parseNovels(loadedCheerio: CheerioAPI) { parseNovels(loadedCheerio: CheerioAPI) {
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
@@ -143,14 +148,6 @@ class NovelBin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url, {
headers: {
'referrer': this.site,
},
});
}
filters = { filters = {
sort: { sort: {
value: 'popular-novels', value: 'popular-novels',
-4
View File
@@ -169,10 +169,6 @@ class NovelBuddy implements Plugin.PluginBase {
const loadedCheerio = parseHTML(body); const loadedCheerio = parseHTML(body);
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new NovelBuddy(); export default new NovelBuddy();
-4
View File
@@ -135,10 +135,6 @@ class NovelFull implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
sort: { sort: {
value: 'most-popular', value: 'most-popular',
-3
View File
@@ -126,9 +126,6 @@ class NovelHall implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new NovelHall(); export default new NovelHall();
-4
View File
@@ -713,10 +713,6 @@ class NovelUpdates implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
sort: { sort: {
label: 'Sort Results By', label: 'Sort Results By',
-4
View File
@@ -137,10 +137,6 @@ class PawRead implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
status: { status: {
value: '', value: '',
+108 -119
View File
@@ -19,49 +19,51 @@ class RanobesPlugin implements Plugin.PagePlugin {
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
let tempNovel = {} as Plugin.NovelItem; let tempNovel = {} as Plugin.NovelItem;
tempNovel.name = ''; tempNovel.name = '';
const baseUrl = this.site const baseUrl = this.site;
let isParsingNovel = false; let isParsingNovel = false;
let isTitleTag = false; let isTitleTag = false;
let isNovelName = false; let isNovelName = false;
const parser = new Parser({ const parser = new Parser({
onopentag(name, attribs) { onopentag(name, attribs) {
if (attribs['class']?.includes('short-cont')){ if (attribs['class']?.includes('short-cont')) {
isParsingNovel = true; isParsingNovel = true;
} }
if (isParsingNovel){ if (isParsingNovel) {
if (name === 'h2' && attribs['class']?.includes('title')){ if (name === 'h2' && attribs['class']?.includes('title')) {
isTitleTag = true; isTitleTag = true;
} }
if (isTitleTag && name === 'a'){ if (isTitleTag && name === 'a') {
tempNovel.path = attribs['href'].slice(baseUrl.length); tempNovel.path = attribs['href'].slice(baseUrl.length);
isNovelName = true; isNovelName = true;
} }
if (name === 'figure'){ if (name === 'figure') {
tempNovel.cover = attribs['style'] tempNovel.cover = attribs['style'].replace(
.replace(/.*url\((.*?)\)./g, '$1'); /.*url\((.*?)\)./g,
'$1',
);
} }
if (tempNovel.path && tempNovel.cover){ if (tempNovel.path && tempNovel.cover) {
novels.push(tempNovel); novels.push(tempNovel);
tempNovel = {} as Plugin.NovelItem; tempNovel = {} as Plugin.NovelItem;
tempNovel.name = ''; tempNovel.name = '';
} }
} }
}, },
ontext(data){ ontext(data) {
if(isNovelName){ if (isNovelName) {
tempNovel.name += data; tempNovel.name += data;
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'h2'){ if (name === 'h2') {
isNovelName = false; isNovelName = false;
isTitleTag = false; isTitleTag = false;
} }
if(name === 'figure'){ if (name === 'figure') {
isParsingNovel = false; isParsingNovel = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
return novels; return novels;
@@ -104,7 +106,7 @@ class RanobesPlugin implements Plugin.PagePlugin {
summary: '', summary: '',
chapters: [], chapters: [],
totalPages: 1, totalPages: 1,
} };
let baseUrl = this.site; let baseUrl = this.site;
let isCover = false; let isCover = false;
let isAuthor = false; let isAuthor = false;
@@ -113,108 +115,102 @@ class RanobesPlugin implements Plugin.PagePlugin {
let isStatusText = false; let isStatusText = false;
let isGenres = false; let isGenres = false;
let isGenresText = false; let isGenresText = false;
let genreArray: string[] = [] let genreArray: string[] = [];
let novelId = ''; let novelId = '';
const parser = new Parser ({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if (attribs['class'] === 'poster'){ if (attribs['class'] === 'poster') {
isCover = true; isCover = true;
} }
if (isCover && name === 'img'){ if (isCover && name === 'img') {
novel.name = attribs['alt']; novel.name = attribs['alt'];
novel.cover = baseUrl + attribs['src']; novel.cover = baseUrl + attribs['src'];
} }
if (name === 'div' && attribs['class'] === 'moreless'){ if (name === 'div' && attribs['class'] === 'moreless') {
isSummary = true; isSummary = true;
} }
if (name === 'li' && attribs['title']?.includes('Original status')){ if (name === 'li' && attribs['title']?.includes('Original status')) {
isStatus = true; isStatus = true;
} }
if (name === 'input' && attribs['name'] === 'newsid'){ if (name === 'input' && attribs['name'] === 'newsid') {
novelId = attribs['value'] novelId = attribs['value'];
} }
}, },
onopentagname(name){ onopentagname(name) {
if (isSummary && name === 'br'){ if (isSummary && name === 'br') {
novel.summary += `/n`; novel.summary += `/n`;
} }
if (isStatus && name === 'a'){ if (isStatus && name === 'a') {
isStatusText = true; isStatusText = true;
} }
if (isGenres && name === 'a'){ if (isGenres && name === 'a') {
isGenresText = true; isGenresText = true;
} }
}, },
onattribute(name,value){ onattribute(name, value) {
if (name === 'itemprop' && value === 'creator'){ if (name === 'itemprop' && value === 'creator') {
isAuthor = true; isAuthor = true;
} }
if (name === 'id' && value === 'mc-fs-genre'){ if (name === 'id' && value === 'mc-fs-genre') {
isGenres = true; isGenres = true;
} }
}, },
ontext(data){ ontext(data) {
if(isAuthor){ if (isAuthor) {
novel.author = data; novel.author = data;
} }
if(isSummary){ if (isSummary) {
novel.summary += data; novel.summary += data;
} }
if(isStatusText){ if (isStatusText) {
novel.status = data === 'Ongoing' novel.status = data === 'Ongoing' ? 'Ongoing' : 'Completed';
? 'Ongoing'
: 'Completed';
} }
if(isGenresText){ if (isGenresText) {
genreArray.push(data); genreArray.push(data);
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'a'){ if (name === 'a') {
isCover = false; isCover = false;
isAuthor = false; isAuthor = false;
isStatusText = false; isStatusText = false;
isGenresText = false; isGenresText = false;
isStatus = false; isStatus = false;
} }
if(name === 'div'){ if (name === 'div') {
isSummary = false; isSummary = false;
isGenres = false; isGenres = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
novel.genres = genreArray.join(', '); novel.genres = genreArray.join(', ');
const chapterListUrl = this.site + '/chapters/' + novelId + '/'; const chapterListUrl = this.site + '/chapters/' + novelId + '/';
const chaptersHtml = await fetchApi(chapterListUrl).then(r => const chaptersHtml = await fetchApi(chapterListUrl).then(r => r.text());
r.text(), let dataJson: {
); pages_count: string;
let dataJson: { chapters: ChapterEntry[];
pages_count: string, } = { pages_count: '', chapters: [] };
chapters: ChapterEntry[]
} = { pages_count: '', chapters : [] };
let isScript = false; let isScript = false;
const parser2 = new Parser ({ const parser2 = new Parser({
ontext(data){ ontext(data) {
if(isScript){ if (isScript) {
if (data.includes('window.__DATA__ =')){ if (data.includes('window.__DATA__ =')) {
dataJson = JSON.parse( dataJson = JSON.parse(data.replace('window.__DATA__ =', ''));
data.replace('window.__DATA__ =', '')
);
} }
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'main'){ if (name === 'main') {
isScript = true; isScript = true;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
}, },
}) });
parser2.write(chaptersHtml); parser2.write(chaptersHtml);
parser2.end(); parser2.end();
@@ -241,29 +237,27 @@ class RanobesPlugin implements Plugin.PagePlugin {
const pageUrl = firstUrl + '/page/' + page; const pageUrl = firstUrl + '/page/' + page;
const pageBody = await fetchApi(pageUrl).then(r => r.text()); const pageBody = await fetchApi(pageUrl).then(r => r.text());
let isScript = false; let isScript = false;
let dataJson: { let dataJson: {
pages_count: string, pages_count: string;
chapters: ChapterEntry[] chapters: ChapterEntry[];
} = { pages_count: '', chapters : [] }; } = { pages_count: '', chapters: [] };
const parser = new Parser({ const parser = new Parser({
ontext(data){ ontext(data) {
if(isScript){ if (isScript) {
if (data.includes('window.__DATA__ =')){ if (data.includes('window.__DATA__ =')) {
dataJson = JSON.parse( dataJson = JSON.parse(data.replace('window.__DATA__ =', ''));
data.replace('window.__DATA__ =', '')
);
} }
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'main'){ if (name === 'main') {
isScript = true; isScript = true;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
} },
}) });
parser.write(pageBody); parser.write(pageBody);
parser.end(); parser.end();
const chapters = this.parseChapters(dataJson); const chapters = this.parseChapters(dataJson);
@@ -280,92 +274,92 @@ class RanobesPlugin implements Plugin.PagePlugin {
let isPtag = false; let isPtag = false;
let isStyleText = false; let isStyleText = false;
const parser = new Parser({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
let stylediv = attribs['style'] let stylediv = attribs['style'];
if(stylediv){ if (stylediv) {
chapterText += `<div style="${stylediv}">` chapterText += `<div style="${stylediv}">`;
isStyleText = true; isStyleText = true;
} else { } else {
chapterText += `<div>` chapterText += `<div>`;
} }
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
let w = attribs['width']; let w = attribs['width'];
if(w) { if (w) {
chapterText += `<table width="${w}">`; chapterText += `<table width="${w}">`;
} else { } else {
chapterText += `<table>`; chapterText += `<table>`;
} }
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `<tbody>`; chapterText += `<tbody>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `<tr>`; chapterText += `<tr>`;
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
let w1 = attribs['width']; let w1 = attribs['width'];
if(w1) { if (w1) {
chapterText += `<td width="${w1}">`; chapterText += `<td width="${w1}">`;
} else { } else {
chapterText += `<td>`; chapterText += `<td>`;
} }
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'id' && value === 'arrticle'){ if (name === 'id' && value === 'arrticle') {
isChapter = true; isChapter = true;
} }
if (name === 'class' && value === 'category grey ellipses'){ if (name === 'class' && value === 'category grey ellipses') {
isChapter = false; isChapter = false;
isPtag = false; isPtag = false;
} }
}, },
onopentagname(name){ onopentagname(name) {
if (isChapter && name === 'p'){ if (isChapter && name === 'p') {
chapterText += '<p>'; chapterText += '<p>';
isPtag = true; isPtag = true;
if(isStyleText){ if (isStyleText) {
isStyleText = false; isStyleText = false;
} }
} }
if (isChapter && name === 'br'){ if (isChapter && name === 'br') {
chapterText += `<br>`; chapterText += `<br>`;
} }
}, },
ontext(data){ ontext(data) {
if(isPtag){ if (isPtag) {
chapterText += data; chapterText += data;
} }
if(isStyleText){ if (isStyleText) {
chapterText += data; chapterText += data;
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'p'){ if (name === 'p') {
isPtag = false; isPtag = false;
chapterText += '</p>' chapterText += '</p>';
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
chapterText += `</td>`; chapterText += `</td>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `</tr>`; chapterText += `</tr>`;
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `</tbody>`; chapterText += `</tbody>`;
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
chapterText += `</table>`; chapterText += `</table>`;
} }
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
isStyleText = false; isStyleText = false;
chapterText += `</div>` chapterText += `</div>`;
} }
} },
}) });
parser.write(html) parser.write(html);
parser.end(); parser.end();
return chapterText; return chapterText;
@@ -380,11 +374,6 @@ class RanobesPlugin implements Plugin.PagePlugin {
return this.parseNovels(body); return this.parseNovels(body);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
} }
export default new RanobesPlugin(); export default new RanobesPlugin();
@@ -393,4 +382,4 @@ interface ChapterEntry {
title: string; title: string;
date: string; date: string;
link: string; link: string;
} }
-4
View File
@@ -174,10 +174,6 @@ class ReadLiteNovel implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
order: { order: {
value: 'top-rated', value: 'top-rated',
-4
View File
@@ -382,10 +382,6 @@ class ReLibraryPlugin implements Plugin.PluginBase {
this.searchFunc.setHaystack(novels); this.searchFunc.setHaystack(novels);
return this.searchFunc.search(searchTerm); return this.searchFunc.search(searchTerm);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url, { headers: { referer: this.site } });
}
} }
export default new ReLibraryPlugin(); export default new ReLibraryPlugin();
+91 -95
View File
@@ -18,37 +18,37 @@ class RoyalRoad implements Plugin.PluginBase {
let isParsingNovel = false; let isParsingNovel = false;
let isNovelName = false; let isNovelName = false;
const parser = new Parser({ const parser = new Parser({
onopentag(name, attribs){ onopentag(name, attribs) {
if (attribs['class']?.includes('fiction-list-item')){ if (attribs['class']?.includes('fiction-list-item')) {
isParsingNovel = true; isParsingNovel = true;
} }
if (isParsingNovel){ if (isParsingNovel) {
if (name === 'a' && attribs['class']?.includes('bold')){ if (name === 'a' && attribs['class']?.includes('bold')) {
tempNovel.path = attribs['href'].slice(1); tempNovel.path = attribs['href'].slice(1);
isNovelName = true; isNovelName = true;
} }
if (name === 'img'){ if (name === 'img') {
tempNovel.cover = attribs['src']; tempNovel.cover = attribs['src'];
} }
if (tempNovel.path && tempNovel.name){ if (tempNovel.path && tempNovel.name) {
novels.push(tempNovel); novels.push(tempNovel);
tempNovel = {} as Plugin.NovelItem; tempNovel = {} as Plugin.NovelItem;
tempNovel.name = ''; tempNovel.name = '';
} }
} }
}, },
ontext(data){ ontext(data) {
if(isNovelName){ if (isNovelName) {
tempNovel.name += data; tempNovel.name += data;
} }
}, },
onclosetag(name){ onclosetag(name) {
if(name === 'h2'){ if (name === 'h2') {
isNovelName = false; isNovelName = false;
isParsingNovel = false; isParsingNovel = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
return novels; return novels;
@@ -64,9 +64,9 @@ class RoyalRoad implements Plugin.PluginBase {
link += `?page=${page}`; link += `?page=${page}`;
if (filters.genre.value !== '') link += `&genre=${filters.genre.value}`; if (filters.genre.value !== '') link += `&genre=${filters.genre.value}`;
const body = await fetchApi(link).then(r => r.text()); const body = await fetchApi(link).then(r => r.text());
return this.parseNovels(body); return this.parseNovels(body);
} }
@@ -78,110 +78,110 @@ class RoyalRoad implements Plugin.PluginBase {
name: '', name: '',
summary: '', summary: '',
chapters: [], chapters: [],
} };
let isNovelName = false; let isNovelName = false;
let isAuthorName = false; let isAuthorName = false;
let isDescription = false; let isDescription = false;
let isH4 = false; let isH4 = false;
let isSpan = 0 let isSpan = 0;
let isTags = false; let isTags = false;
let isGenres = false; let isGenres = false;
let genreArray: string[] = [] let genreArray: string[] = [];
let isFooter = false; let isFooter = false;
let isScript = false; let isScript = false;
let chapterJson: ChapterEntry[] = []; let chapterJson: ChapterEntry[] = [];
let volumeJson: VolumeEntry[] = []; let volumeJson: VolumeEntry[] = [];
const parser = new Parser ({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if (name === 'img' && attribs['class']?.includes('thumbnail')){ if (name === 'img' && attribs['class']?.includes('thumbnail')) {
novel.cover = attribs['src']; novel.cover = attribs['src'];
} }
if (name === 'span' && attribs['class']?.includes('label-sm')){ if (name === 'span' && attribs['class']?.includes('label-sm')) {
isSpan++; isSpan++;
} }
if (name === 'span' && attribs['class']?.includes('tags')){ if (name === 'span' && attribs['class']?.includes('tags')) {
isTags = true; isTags = true;
} }
}, },
onopentagname(name){ onopentagname(name) {
if (name === 'h1'){ if (name === 'h1') {
isNovelName = true; isNovelName = true;
} }
if (isH4 && name === 'a'){ if (isH4 && name === 'a') {
isAuthorName = true; isAuthorName = true;
} }
if(isTags && name === 'a'){ if (isTags && name === 'a') {
isGenres = true; isGenres = true;
} }
if (name === 'label'){ if (name === 'label') {
isDescription = false; isDescription = false;
isTags = false; isTags = false;
} }
if (isFooter && name === 'script'){ if (isFooter && name === 'script') {
isScript = true; isScript = true;
} }
}, },
onattribute(name,value){ onattribute(name, value) {
if (name === 'class' && value === 'description'){ if (name === 'class' && value === 'description') {
isDescription = true; isDescription = true;
} }
if (name === 'class' && value === 'page-footer footer'){ if (name === 'class' && value === 'page-footer footer') {
isFooter = true; isFooter = true;
} }
}, },
ontext(data){ ontext(data) {
if (isNovelName){ if (isNovelName) {
novel.name = data; novel.name = data;
} }
if (isAuthorName){ if (isAuthorName) {
novel.author = data; novel.author = data;
isAuthorName = false; isAuthorName = false;
} }
if (isDescription){ if (isDescription) {
novel.summary += data; novel.summary += data;
} }
if (isSpan === 2){ if (isSpan === 2) {
novel.status = data.trim(); novel.status = data.trim();
isSpan++; isSpan++;
} }
if (isGenres){ if (isGenres) {
genreArray.push(data); genreArray.push(data);
} }
if (isScript){ if (isScript) {
if (data.includes('window.chapters =')){ if (data.includes('window.chapters =')) {
chapterJson = JSON.parse( chapterJson = JSON.parse(
data.match(/window.chapters = (.+])(?=;)/)![1] data.match(/window.chapters = (.+])(?=;)/)![1],
) );
volumeJson = JSON.parse( volumeJson = JSON.parse(
data.match(/window.volumes = (.+])(?=;)/)![1] data.match(/window.volumes = (.+])(?=;)/)![1],
) );
} }
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'h1'){ if (name === 'h1') {
isNovelName = false; isNovelName = false;
isH4 = true; isH4 = true;
} }
if (name === 'h4'){ if (name === 'h4') {
isH4 = false; isH4 = false;
} }
if (name === 'a'){ if (name === 'a') {
isGenres = false; isGenres = false;
} }
if (name === 'script'){ if (name === 'script') {
isScript = false; isScript = false;
} }
if (name === 'body'){ if (name === 'body') {
isFooter = false; isFooter = false;
} }
} },
}) });
parser.write(html); parser.write(html);
parser.end(); parser.end();
novel.summary = novel.summary?.trim(); novel.summary = novel.summary?.trim();
novel.genres = genreArray.join(', '); novel.genres = genreArray.join(', ');
switch(novel.status){ switch (novel.status) {
case 'ONGOING': case 'ONGOING':
novel.status = NovelStatus.Ongoing; novel.status = NovelStatus.Ongoing;
break; break;
@@ -224,106 +224,106 @@ class RoyalRoad implements Plugin.PluginBase {
let isStyleText = false; let isStyleText = false;
let styles = ''; let styles = '';
const parser = new Parser({ const parser = new Parser({
onopentag(name,attribs){ onopentag(name, attribs) {
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
let stylediv = attribs['style'] let stylediv = attribs['style'];
if(stylediv){ if (stylediv) {
chapterText += `<div style="${stylediv}">` chapterText += `<div style="${stylediv}">`;
isStyleText = true; isStyleText = true;
} else { } else {
chapterText += `<div>` chapterText += `<div>`;
} }
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
let w = attribs['width']; let w = attribs['width'];
if(w) { if (w) {
chapterText += `<table width="${w}">`; chapterText += `<table width="${w}">`;
} else { } else {
chapterText += `<table>`; chapterText += `<table>`;
} }
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `<tbody>`; chapterText += `<tbody>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `<tr>`; chapterText += `<tr>`;
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
let w1 = attribs['width']; let w1 = attribs['width'];
if(w1) { if (w1) {
chapterText += `<td width="${w1}">`; chapterText += `<td width="${w1}">`;
} else { } else {
chapterText += `<td>`; chapterText += `<td>`;
} }
} }
}, },
onattribute(name, value){ onattribute(name, value) {
if (name === 'class' && value === 'chapter-inner chapter-content'){ if (name === 'class' && value === 'chapter-inner chapter-content') {
isChapter = true; isChapter = true;
} }
if (name === 'class' && value === 'portlet light t-center-3'){ if (name === 'class' && value === 'portlet light t-center-3') {
isChapter = false; isChapter = false;
isPtag = false; isPtag = false;
} }
if (name === 'class' && value === styles){ if (name === 'class' && value === styles) {
isPtag = false; isPtag = false;
} }
}, },
onopentagname(name){ onopentagname(name) {
if (isChapter && name === 'p'){ if (isChapter && name === 'p') {
chapterText += '<p>'; chapterText += '<p>';
isPtag = true; isPtag = true;
if(isStyleText){ if (isStyleText) {
isStyleText = false; isStyleText = false;
} }
} }
if (name === 'style'){ if (name === 'style') {
isStyle = true; isStyle = true;
} }
if (isChapter && name === 'br'){ if (isChapter && name === 'br') {
chapterText += `<br>`; chapterText += `<br>`;
} }
}, },
ontext(data){ ontext(data) {
if(isPtag){ if (isPtag) {
chapterText += data; chapterText += data;
} }
if(isStyleText){ if (isStyleText) {
chapterText += data; chapterText += data;
} }
if (isStyle){ if (isStyle) {
if (data.includes('display: none;')){ if (data.includes('display: none;')) {
styles = data.match(/\.(.*)\{/)![1]; styles = data.match(/\.(.*)\{/)![1];
} }
} }
}, },
onclosetag(name){ onclosetag(name) {
if (name === 'p'){ if (name === 'p') {
isPtag = false; isPtag = false;
chapterText += '</p>' chapterText += '</p>';
} }
if (name === 'style'){ if (name === 'style') {
isStyle = false; isStyle = false;
} }
if (isChapter && name === 'td'){ if (isChapter && name === 'td') {
chapterText += `</td>`; chapterText += `</td>`;
} }
if (isChapter && name === 'tr'){ if (isChapter && name === 'tr') {
chapterText += `</tr>`; chapterText += `</tr>`;
} }
if (isChapter && name === 'tbody'){ if (isChapter && name === 'tbody') {
chapterText += `</tbody>`; chapterText += `</tbody>`;
} }
if (isChapter && name === 'table'){ if (isChapter && name === 'table') {
chapterText += `</table>`; chapterText += `</table>`;
} }
if (isChapter && name === 'div'){ if (isChapter && name === 'div') {
isStyleText = false; isStyleText = false;
chapterText += `</div>` chapterText += `</div>`;
} }
} },
}) });
parser.write(html) parser.write(html);
parser.end(); parser.end();
return chapterText; return chapterText;
@@ -339,10 +339,6 @@ class RoyalRoad implements Plugin.PluginBase {
return this.parseNovels(body); return this.parseNovels(body);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
order: { order: {
value: 'weekly-popular', value: 'weekly-popular',
-4
View File
@@ -185,10 +185,6 @@ class ScribbleHubPlugin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
sort: { sort: {
label: 'Sort Results By', label: 'Sort Results By',
-1
View File
@@ -170,7 +170,6 @@ class WTRLAB implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
order: { order: {
value: 'chapter', value: 'chapter',
-4
View File
@@ -285,10 +285,6 @@ class WuxiaWorld implements Plugin.PluginBase {
return this.parseNovels(data); return this.parseNovels(data);
} }
fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
proto = ` proto = `
syntax = "proto3"; syntax = "proto3";
option optimize_for = CODE_SIZE; option optimize_for = CODE_SIZE;
-2
View File
@@ -250,8 +250,6 @@ class ChireadsPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
tag: { tag: {
type: FilterTypes.Picker, type: FilterTypes.Picker,
-6
View File
@@ -173,12 +173,6 @@ class HarkenEliwoodPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new HarkenEliwoodPlugin(); export default new HarkenEliwoodPlugin();
-2
View File
@@ -292,8 +292,6 @@ class NovelDeGlacePlugin implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
categorie_genre: { categorie_genre: {
type: FilterTypes.Picker, type: FilterTypes.Picker,
-6
View File
@@ -202,12 +202,6 @@ class NovhellPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new NovhellPlugin(); export default new NovhellPlugin();
-7
View File
@@ -172,13 +172,6 @@ class PhenixScansTradPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
const headers = new Headers({
'Referer': `${this.site}`,
});
return await fetchFile(url, { headers });
}
filters = { filters = {
genre: { genre: {
type: FilterTypes.CheckboxGroup, type: FilterTypes.CheckboxGroup,
-6
View File
@@ -193,12 +193,6 @@ class WarriorLegendTradPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new WarriorLegendTradPlugin(); export default new WarriorLegendTradPlugin();
-6
View File
@@ -211,12 +211,6 @@ class WuxialnscantradPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new WuxialnscantradPlugin(); export default new WuxialnscantradPlugin();
-6
View File
@@ -293,12 +293,6 @@ class XiaowazPlugin implements Plugin.PluginBase {
return await this.getNovelsCovers(novels); return await this.getNovelsCovers(novels);
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
} }
export default new XiaowazPlugin(); export default new XiaowazPlugin();
-4
View File
@@ -131,10 +131,6 @@ class IndoWebNovel implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
status: { status: {
value: '', value: '',
-4
View File
@@ -140,10 +140,6 @@ class NovelRingan implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
status: { status: {
value: '', value: '',
-4
View File
@@ -159,10 +159,6 @@ class SakuraNovel implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
status: { status: {
value: '', value: '',
+1 -3
View File
@@ -217,9 +217,7 @@ class Syosetu implements Plugin.PluginBase {
// respond with novels! // respond with novels!
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
resolveUrl(path: string, isNovel?: boolean | undefined): string { resolveUrl(path: string, isNovel?: boolean | undefined): string {
return this.novelPrefix + path; return this.novelPrefix + path;
} }
-1
View File
@@ -155,7 +155,6 @@ class Agitoon implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + (isNovel ? '/novel/list/' : '/novel/view/') + path; this.site + (isNovel ? '/novel/list/' : '/novel/view/') + path;
} }
+1 -5
View File
@@ -165,11 +165,7 @@ class NovelkiPL implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
// if your plugin has images and they won't load
// this is the function to fiddle with
return fetchFile(url);
}
filters = { filters = {
genres: { genres: {
value: '', value: '',
-2
View File
@@ -151,8 +151,6 @@ class freedlit implements Plugin.PluginBase {
return dateString || null; return dateString || null;
}; };
fetchImage = fetchFile;
filters = { filters = {
sort: { sort: {
label: 'Сортировка:', label: 'Сортировка:',
-1
View File
@@ -175,7 +175,6 @@ class AuthorToday implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
isNovel ? this.site + '/work/' + path : this.site + '/reader/' + path; isNovel ? this.site + '/work/' + path : this.site + '/reader/' + path;
-1
View File
@@ -138,7 +138,6 @@ class Bookriver implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + (isNovel ? '/book/' : '/reader/') + path; this.site + (isNovel ? '/book/' : '/reader/') + path;
-2
View File
@@ -197,8 +197,6 @@ class ficbook implements Plugin.PluginBase {
return dateString || null; return dateString || null;
}; };
fetchImage = fetchFile;
filters = { filters = {
sort: { sort: {
label: 'Сортировка:', label: 'Сортировка:',
-2
View File
@@ -193,8 +193,6 @@ class Jaomix implements Plugin.PluginBase {
return dateString || null; return dateString || null;
}; };
fetchImage = fetchFile;
filters = { filters = {
sortby: { sortby: {
label: 'Сортировка:', label: 'Сортировка:',
-1
View File
@@ -143,7 +143,6 @@ class Neobook implements Plugin.PluginBase {
return chapterText; return chapterText;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + (isNovel ? '/book/' : '/reader/') + path; this.site + (isNovel ? '/book/' : '/reader/') + path;
-1
View File
@@ -158,7 +158,6 @@ class novelOvh implements Plugin.PluginBase {
return html; return html;
}; };
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + '/novel/' + path; this.site + '/novel/' + path;
-1
View File
@@ -195,7 +195,6 @@ class TL implements Plugin.PluginBase {
return chapterText; return chapterText;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => 'https://' + path; resolveUrl = (path: string, isNovel?: boolean) => 'https://' + path;
filters = { filters = {
-1
View File
@@ -164,7 +164,6 @@ class RNBH implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + '/ranobe/' + path; this.site + '/ranobe/' + path;
-1
View File
@@ -216,7 +216,6 @@ class RLIB implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => { resolveUrl = (path: string, isNovel?: boolean) => {
const ui = this.user?.ui ? 'ui=' + this.user.ui : ''; const ui = this.user?.ui ? 'ui=' + this.user.ui : '';
-2
View File
@@ -134,8 +134,6 @@ class RNRF implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
filters = { filters = {
sort: { sort: {
label: 'Сортировка', label: 'Сортировка',
-1
View File
@@ -147,7 +147,6 @@ class ReN implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + '/novel/' + path; this.site + '/novel/' + path;
-1
View File
@@ -190,7 +190,6 @@ class Zelluloza implements Plugin.PluginBase {
return null; return null;
}; };
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => resolveUrl = (path: string, isNovel?: boolean) =>
this.site + '/books/' + path; this.site + '/books/' + path;
-3
View File
@@ -136,9 +136,6 @@ class HasulTL implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new HasulTL(); export default new HasulTL();
-3
View File
@@ -176,9 +176,6 @@ class Ligera implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new Ligera(); export default new Ligera();
-3
View File
@@ -199,9 +199,6 @@ class ReinoWuxia implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new ReinoWuxia(); export default new ReinoWuxia();
-3
View File
@@ -161,9 +161,6 @@ class Oasis implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new Oasis(); export default new Oasis();
-3
View File
@@ -128,9 +128,6 @@ class SkyNovels implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new SkyNovels(); export default new SkyNovels();
-4
View File
@@ -182,10 +182,6 @@ class TuNovelaLigera implements Plugin.PagePlugin {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
order: { order: {
value: 'rating', value: 'rating',
-3
View File
@@ -179,9 +179,6 @@ class Yuuki implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new Yuuki(); export default new Yuuki();
-3
View File
@@ -159,9 +159,6 @@ class EpikNovel implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new EpikNovel(); export default new EpikNovel();
-3
View File
@@ -166,9 +166,6 @@ class LSHNovel implements Plugin.PluginBase {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return await fetchFile(url);
}
filters = { filters = {
order: { order: {
-2
View File
@@ -113,8 +113,6 @@ class Smakolykytl implements Plugin.PluginBase {
); );
return novels; return novels;
} }
fetchImage = fetchFile;
} }
export default new Smakolykytl(); export default new Smakolykytl();
+6 -6
View File
@@ -1,5 +1,4 @@
import { Parser } from 'htmlparser2'; import { Parser } from 'htmlparser2';
import { fetchFile } from '@libs/fetch';
import { HTMLParser2Util, Plugin } from '@typings/plugin'; import { HTMLParser2Util, Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
import { FilterTypes, Filters } from '@libs/filterInputs'; import { FilterTypes, Filters } from '@libs/filterInputs';
@@ -395,6 +394,8 @@ class HakoPlugin implements Plugin.PluginBase {
novel.status = NovelStatus.Unknown; novel.status = NovelStatus.Unknown;
} }
novel.genres = novel.genres?.replace(/,*\s*$/, ''); novel.genres = novel.genres?.replace(/,*\s*$/, '');
novel.name = novel.name.trim();
novel.summary = novel.summary?.trim();
return novel; return novel;
}); });
} }
@@ -416,12 +417,11 @@ class HakoPlugin implements Plugin.PluginBase {
this.site + '/tim-kiem?keywords=' + searchTerm + '&page=' + pageNo; this.site + '/tim-kiem?keywords=' + searchTerm + '&page=' + pageNo;
return this.parseNovels(url); return this.parseNovels(url);
} }
fetchImage(url: string): Promise<string | undefined> { imageRequestInit: Plugin.ImageRequestInit = {
const headers = { headers: {
Referer: 'https://ln.hako.vn', Referer: 'https://ln.hako.vn',
}; },
return fetchFile(url, { headers: headers }); };
}
filters = { filters = {
alphabet: { alphabet: {
type: FilterTypes.Picker, type: FilterTypes.Picker,
+1 -3
View File
@@ -247,9 +247,7 @@ class TruyenConect implements Plugin.PagePlugin {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
filters = { filters = {
category: { category: {
label: 'Lọc theo', label: 'Lọc theo',
-3
View File
@@ -170,9 +170,6 @@ class LightNovelVN implements Plugin.PagePlugin {
}) || []; }) || [];
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new LightNovelVN(); export default new LightNovelVN();
-3
View File
@@ -119,8 +119,5 @@ class Nettruyen implements Plugin.PagePlugin {
): Promise<Plugin.NovelItem[]> { ): Promise<Plugin.NovelItem[]> {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new Nettruyen(); export default new Nettruyen();
-3
View File
@@ -151,9 +151,6 @@ class TruyenFull implements Plugin.PagePlugin {
const loadedCheerio = parseHTML(body); const loadedCheerio = parseHTML(body);
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new TruyenFull(); export default new TruyenFull();
-3
View File
@@ -142,9 +142,6 @@ class TruyenFull implements Plugin.PagePlugin {
const loadedCheerio = parseHTML(body); const loadedCheerio = parseHTML(body);
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url);
}
} }
export default new TruyenFull(); export default new TruyenFull();
+1 -3
View File
@@ -1,4 +1,4 @@
import { fetchFile, fetchApi } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
@@ -162,8 +162,6 @@ class HotNovelPubPlugin implements Plugin.PluginBase {
return novels; return novels;
} }
fetchImage = fetchFile;
resolveUrl = (path: string, isNovel?: boolean) => this.site + '/' + path; resolveUrl = (path: string, isNovel?: boolean) => this.site + '/' + path;
} }
+1 -3
View File
@@ -1,4 +1,4 @@
import { fetchFile, fetchApi } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
@@ -216,6 +216,4 @@ class IfreedomPlugin implements Plugin.PluginBase {
} }
return dateString || null; return dateString || null;
}; };
fetchImage = fetchFile;
} }
+4 -5
View File
@@ -1,5 +1,5 @@
import { load as parseHTML } from 'cheerio'; import { load as parseHTML } from 'cheerio';
import { fetchApi, fetchFile } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
@@ -27,6 +27,9 @@ class LightNovelWorld implements Plugin.PagePlugin {
Accept: 'application/json', Accept: 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}; };
imageRequestInit?: Plugin.ImageRequestInit | undefined = {
headers: this.headers,
};
options?: LightNovelWorldOptions; options?: LightNovelWorldOptions;
constructor(metadata: LightNovelWorldMetadata) { constructor(metadata: LightNovelWorldMetadata) {
@@ -188,10 +191,6 @@ class LightNovelWorld implements Plugin.PagePlugin {
return novels; return novels;
} }
async fetchImage(url: string): Promise<string | undefined> {
return fetchFile(url, { headers: this.headers });
}
filters = { filters = {
order: { order: {
value: 'popular', value: 'popular',
+1 -3
View File
@@ -1,6 +1,6 @@
import { load } from 'cheerio'; import { load } from 'cheerio';
import { Parser } from 'htmlparser2'; import { Parser } from 'htmlparser2';
import { fetchApi, fetchFile } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
import { defaultCover } from '@libs/defaultCover'; import { defaultCover } from '@libs/defaultCover';
@@ -407,8 +407,6 @@ class LightNovelWPPlugin implements Plugin.PluginBase {
const html = await this.safeFecth(url, true); const html = await this.safeFecth(url, true);
return this.parseNovels(html); return this.parseNovels(html);
} }
fetchImage = fetchFile;
} }
function extractChapterNumber(data: string, tempChapter: Plugin.ChapterItem) { function extractChapterNumber(data: string, tempChapter: Plugin.ChapterItem) {
+1 -3
View File
@@ -1,4 +1,4 @@
import { fetchApi, fetchFile } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { Cheerio, AnyNode, CheerioAPI, load as parseHTML } from 'cheerio'; import { Cheerio, AnyNode, CheerioAPI, load as parseHTML } from 'cheerio';
@@ -294,8 +294,6 @@ class MadaraPlugin implements Plugin.PluginBase {
return this.parseNovels(loadedCheerio); return this.parseNovels(loadedCheerio);
} }
fetchImage = fetchFile;
parseData = (date: string) => { parseData = (date: string) => {
const dayJSDate = dayjs(); // today const dayJSDate = dayjs(); // today
const timeAgo = date.match(/\d+/)?.[0] || ''; const timeAgo = date.match(/\d+/)?.[0] || '';
+1 -3
View File
@@ -1,5 +1,5 @@
import { CheerioAPI, load } from 'cheerio'; import { CheerioAPI, load } from 'cheerio';
import { fetchApi, fetchFile } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
@@ -172,6 +172,4 @@ class ReadNovelFullPlugin implements Plugin.PluginBase {
return this.parseNovels($); return this.parseNovels($);
} }
fetchImage = fetchFile;
} }
+1 -3
View File
@@ -1,4 +1,4 @@
import { fetchFile, fetchApi } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
@@ -223,6 +223,4 @@ class ReadwnPlugin implements Plugin.PluginBase {
.filter(novel => novel.name && novel.path); .filter(novel => novel.name && novel.path);
return novels; return novels;
} }
fetchImage = fetchFile;
} }
+1 -3
View File
@@ -1,4 +1,4 @@
import { fetchFile, fetchApi } from '@libs/fetch'; import { fetchApi } from '@libs/fetch';
import { Filters, FilterTypes } from '@libs/filterInputs'; import { Filters, FilterTypes } from '@libs/filterInputs';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { NovelStatus } from '@libs/novelStatus'; import { NovelStatus } from '@libs/novelStatus';
@@ -246,8 +246,6 @@ class RulatePlugin implements Plugin.PluginBase {
} }
return dateString || null; return dateString || null;
}; };
fetchImage = fetchFile;
} }
interface response { interface response {
+9 -2
View File
@@ -4,6 +4,7 @@ import path from 'path';
import { PluginList } from '@typings/types'; import { PluginList } from '@typings/types';
import { Plugin } from '@typings/plugin'; import { Plugin } from '@typings/plugin';
import { Filters } from '@libs/filterInputs'; import { Filters } from '@libs/filterInputs';
import { fetchFile } from '@libs/fetch';
const root = path.dirname(require?.main?.filename || ''); const root = path.dirname(require?.main?.filename || '');
export const fetchHeaders: Record<string, string> = {}; export const fetchHeaders: Record<string, string> = {};
@@ -83,8 +84,14 @@ export const parseChapter = async (
chapterPath: string, chapterPath: string,
) => (await getPlugin(pluginRequirePath))?.parseChapter(chapterPath); ) => (await getPlugin(pluginRequirePath))?.parseChapter(chapterPath);
export const fetchImage = async (pluginRequirePath: string, url: string) => export const fetchImage = async (pluginRequirePath: string, url: string) => {
(await getPlugin(pluginRequirePath))?.fetchImage(url); const plugin = await getPlugin(pluginRequirePath);
return fetchFile(url, {
method: plugin?.imageRequestInit?.method,
headers: plugin?.imageRequestInit?.headers,
body: plugin?.imageRequestInit?.body,
});
};
export const resolveUrl = async ( export const resolveUrl = async (
pluginRequirePath: string, pluginRequirePath: string,
+6 -1
View File
@@ -53,6 +53,11 @@ export namespace Plugin {
requirePath: string; requirePath: string;
icon: string; icon: string;
} }
export interface ImageRequestInit {
method?: string;
headers?: Record<string, string>;
body?: string;
}
export interface PluginBase { export interface PluginBase {
id: string; id: string;
@@ -65,6 +70,7 @@ export namespace Plugin {
*/ */
icon: string; icon: string;
site: string; site: string;
imageRequestInit?: ImageRequestInit;
filters?: Filters; filters?: Filters;
version: string; version: string;
//flag indicates whether access to LocalStorage, SesesionStorage is required. //flag indicates whether access to LocalStorage, SesesionStorage is required.
@@ -93,7 +99,6 @@ export namespace Plugin {
* return await fetchFile(url, { headers: headers }); * return await fetchFile(url, { headers: headers });
* ``` * ```
*/ */
fetchImage(url: string): Promise<string | undefined>;
resolveUrl?(path: string, isNovel?: boolean): string; resolveUrl?(path: string, isNovel?: boolean): string;
} }