@@ -28,10 +28,32 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
this.name = metadata.sourceName;
|
||||
this.icon = 'multisrc/ranobes/ranobes/icon.png';
|
||||
this.site = metadata.sourceSite;
|
||||
this.version = '2.0.1';
|
||||
this.version = '2.0.2';
|
||||
this.options = metadata.options as RanobesOptions;
|
||||
}
|
||||
|
||||
async safeFecth(url: string, init: any = {}): Promise<string> {
|
||||
const r = await fetchApi(url, init);
|
||||
if (!r.ok)
|
||||
throw new Error(
|
||||
'Could not reach site (' + r.status + ') try to open in webview.',
|
||||
);
|
||||
const data = await r.text();
|
||||
const title = data.match(/<title>(.*?)<\/title>/)?.[1]?.trim();
|
||||
|
||||
if (
|
||||
title &&
|
||||
(title == 'Bot Verification' ||
|
||||
title == 'You are being redirected...' ||
|
||||
title == 'Un instant...' ||
|
||||
title == 'Just a moment...' ||
|
||||
title == 'Redirecting...')
|
||||
)
|
||||
throw new Error('Captcha error, please open in webview');
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
parseNovels(html: string) {
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
let tempNovel = {} as Plugin.NovelItem;
|
||||
@@ -154,7 +176,7 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
|
||||
async popularNovels(page: number): Promise<Plugin.NovelItem[]> {
|
||||
const link = `${this.site}/${this.options.path}/page/${page}/`;
|
||||
const body = await fetchApi(link).then(r => r.text());
|
||||
const body = await this.safeFecth(link);
|
||||
return this.parseNovels(body);
|
||||
}
|
||||
|
||||
@@ -162,8 +184,7 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
novelPath: string,
|
||||
): Promise<Plugin.SourceNovel & { totalPages: number }> {
|
||||
const baseUrl = this.site;
|
||||
const result = await fetchApi(baseUrl + novelPath);
|
||||
const html = await result.text();
|
||||
const html = await this.safeFecth(baseUrl + novelPath);
|
||||
const novel: Plugin.SourceNovel & { totalPages: number } = {
|
||||
path: novelPath,
|
||||
name: '',
|
||||
@@ -330,9 +351,7 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
: '/' + novelPath.split('-').slice(1).join('-').split('.')[0];
|
||||
const firstUrl =
|
||||
this.site + '/chapters' + pagePath.replace(this.options.path + '/', '');
|
||||
const pageBody = await fetchApi(firstUrl + '/page/' + page).then(r =>
|
||||
r.text(),
|
||||
);
|
||||
const pageBody = await this.safeFecth(firstUrl + '/page/' + page);
|
||||
|
||||
const baseUrl = this.site;
|
||||
let isScript = false;
|
||||
@@ -408,8 +427,7 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const result = await fetchApi(this.site + chapterPath);
|
||||
const html = await result.text();
|
||||
const html = await this.safeFecth(this.site + chapterPath);
|
||||
|
||||
const indexA = html.indexOf('<div class="text" id="arrticle">');
|
||||
const indexB = html.indexOf('<div class="category grey ellipses">', indexA);
|
||||
@@ -424,7 +442,7 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
let html;
|
||||
if (this.id === 'ranobes-ru') {
|
||||
html = await fetchApi(this.site + '/index.php?do=search', {
|
||||
html = await this.safeFecth(this.site + '/index.php?do=search', {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Referer: this.site + '/',
|
||||
@@ -436,10 +454,10 @@ class RanobesPlugin implements Plugin.PluginBase {
|
||||
search_start: page.toString(),
|
||||
story: searchTerm,
|
||||
}).toString(),
|
||||
}).then(res => res.text());
|
||||
});
|
||||
} else {
|
||||
const link = `${this.site}/search/${searchTerm}/page/${page}`;
|
||||
html = await fetchApi(link).then(r => r.text());
|
||||
html = await this.safeFecth(link);
|
||||
}
|
||||
return this.parseNovels(html);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,31 @@ class Foxteller implements Plugin.PluginBase {
|
||||
id = 'foxteller';
|
||||
name = 'Foxteller';
|
||||
site = 'https://www.foxteller.com';
|
||||
version = '1.0.1';
|
||||
version = '1.0.2';
|
||||
icon = 'src/en/foxteller/icon.png';
|
||||
|
||||
async safeFecth(url: string, init: any = {}): Promise<string> {
|
||||
const r = await fetchApi(url, init);
|
||||
if (!r.ok)
|
||||
throw new Error(
|
||||
'Could not reach site (' + r.status + ') try to open in webview.',
|
||||
);
|
||||
const data = await r.text();
|
||||
const title = data.match(/<title>(.*?)<\/title>/)?.[1]?.trim();
|
||||
|
||||
if (
|
||||
title &&
|
||||
(title == 'Bot Verification' ||
|
||||
title == 'You are being redirected...' ||
|
||||
title == 'Un instant...' ||
|
||||
title == 'Just a moment...' ||
|
||||
title == 'Redirecting...')
|
||||
)
|
||||
throw new Error('Captcha error, please open in webview');
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async popularNovels(
|
||||
pageNo: number,
|
||||
{ filters }: Plugin.PopularNovelsOptions<typeof this.filters>,
|
||||
@@ -19,7 +41,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
const url =
|
||||
this.site + '/library?sort=' + filters?.order?.value || 'popularity';
|
||||
|
||||
const body = await fetchApi(url).then(res => res.text());
|
||||
const body = await this.safeFecth(url);
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
const div = body.match(/<div class="col-md-6">([\s\S]*?)<\/div>/g) || [];
|
||||
@@ -44,9 +66,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
|
||||
const body = await fetchApi(this.resolveUrl(novelPath)).then(res =>
|
||||
res.text(),
|
||||
);
|
||||
const body = await this.safeFecth(this.resolveUrl(novelPath));
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path: novelPath,
|
||||
name: '',
|
||||
@@ -189,10 +209,9 @@ class Foxteller implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const res = await fetchApi(this.resolveUrl(chapterPath));
|
||||
const body = await res.text();
|
||||
const res = await this.safeFecth(this.resolveUrl(chapterPath));
|
||||
const novelID = chapterPath.split('/')[0];
|
||||
const chapterID = body.match(/'chapter_id': '([\d]+)'/)?.[1];
|
||||
const chapterID = res.match(/'chapter_id': '([\d]+)'/)?.[1];
|
||||
|
||||
if (!chapterID) throw new Error('No chapter found');
|
||||
|
||||
@@ -203,7 +222,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
'Accept-Language': 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3',
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
},
|
||||
Referer: res.url,
|
||||
Referer: this.resolveUrl(chapterPath),
|
||||
body: JSON.stringify({ 'x1': novelID, 'x2': chapterID }),
|
||||
}).then(res => res.json());
|
||||
|
||||
@@ -234,7 +253,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
}
|
||||
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const body = await fetchApi(this.site + '/search', {
|
||||
const body = await this.safeFecth(this.site + '/search', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
Accept: 'application/json, text/plain, */*',
|
||||
@@ -243,7 +262,7 @@ class Foxteller implements Plugin.PluginBase {
|
||||
},
|
||||
Referer: this.site,
|
||||
body: JSON.stringify({ query: searchTerm }),
|
||||
}).then(res => res.text());
|
||||
});
|
||||
const novels: Plugin.NovelItem[] = [];
|
||||
|
||||
const items = body.match(/<a.*>([\s\S]*?)<\/a>/g) || [];
|
||||
|
||||
@@ -18,7 +18,7 @@ class RLIB implements Plugin.PluginBase {
|
||||
name = 'RanobeLib';
|
||||
site = 'https://ranobelib.me';
|
||||
apiSite = 'https://api.mangalib.me/api/manga/';
|
||||
version = '2.1.0';
|
||||
version = '2.1.1';
|
||||
icon = 'src/ru/ranobelib/icon.png';
|
||||
webStorageUtilized = true;
|
||||
|
||||
@@ -126,10 +126,10 @@ class RLIB implements Plugin.PluginBase {
|
||||
novel.genres = genres.join(', ');
|
||||
}
|
||||
|
||||
const branch_id: Record<number, string> = {};
|
||||
const branch_name: Record<number, string> = {};
|
||||
if (data.teams.length) {
|
||||
data.teams.forEach(
|
||||
({ name, details }) => (branch_id[details?.branch_id || '0'] = name),
|
||||
({ name, details }) => (branch_name[details?.branch_id || '0'] = name),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,6 +144,7 @@ class RLIB implements Plugin.PluginBase {
|
||||
const chapters: Plugin.ChapterItem[] = [];
|
||||
|
||||
chaptersJSON.data.forEach(chapter =>
|
||||
chapter.branches.forEach(({ branch_id, created_at }) =>
|
||||
chapters.push({
|
||||
name:
|
||||
'Том ' +
|
||||
@@ -158,13 +159,24 @@ class RLIB implements Plugin.PluginBase {
|
||||
'/' +
|
||||
chapter.number +
|
||||
'/' +
|
||||
(chapter.branches[0]?.branch_id || ''),
|
||||
releaseTime: dayjs(chapter.branches[0].created_at).format('LLL'),
|
||||
(branch_id || ''),
|
||||
releaseTime: dayjs(created_at).format('LLL'),
|
||||
chapterNumber: chapter.index,
|
||||
page: branch_id[chapter.branches[0].branch_id || '0'],
|
||||
page: branch_name[branch_id || '0'],
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
if (chapters.length && data.teams.length > 1) {
|
||||
//For whatever reason, the chapters overlap with another page.
|
||||
chapters.sort((chapterA, chapterB) => {
|
||||
if (chapterA.page !== chapterB.page) {
|
||||
return chapterA.page.localeCompare(chapterB.page);
|
||||
}
|
||||
return chapterA.chapterNumber - chapterB.chapterNumber;
|
||||
});
|
||||
}
|
||||
|
||||
novel.chapters = chapters;
|
||||
}
|
||||
|
||||
@@ -509,6 +521,42 @@ function jsonToHtml(json: HTML[], images, html = '') {
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</p>';
|
||||
break;
|
||||
case 'orderedList':
|
||||
html +=
|
||||
'<ol>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</ol>';
|
||||
break;
|
||||
case 'listItem':
|
||||
html +=
|
||||
'<li>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</li>';
|
||||
break;
|
||||
case 'blockquote':
|
||||
html +=
|
||||
'<blockquote>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</blockquote>';
|
||||
break;
|
||||
case 'italic':
|
||||
html +=
|
||||
'<i>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</i>';
|
||||
break;
|
||||
case 'bold':
|
||||
html +=
|
||||
'<b>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</b>';
|
||||
break;
|
||||
case 'underline':
|
||||
html +=
|
||||
'<u>' +
|
||||
(element.content ? jsonToHtml(element.content, images) : '<br>') +
|
||||
'</u>';
|
||||
break;
|
||||
case 'heading':
|
||||
html +=
|
||||
'<h2>' +
|
||||
|
||||
Reference in New Issue
Block a user