fix ranobelib (#1342)

* test

* float

* hotfix

* -float
This commit is contained in:
Rider21
2024-11-29 04:59:20 +03:00
committed by GitHub
parent aaed26b01b
commit 99c5fb5d8f
3 changed files with 130 additions and 45 deletions
+30 -12
View File
@@ -28,10 +28,32 @@ class RanobesPlugin implements Plugin.PluginBase {
this.name = metadata.sourceName; this.name = metadata.sourceName;
this.icon = 'multisrc/ranobes/ranobes/icon.png'; this.icon = 'multisrc/ranobes/ranobes/icon.png';
this.site = metadata.sourceSite; this.site = metadata.sourceSite;
this.version = '2.0.1'; this.version = '2.0.2';
this.options = metadata.options as RanobesOptions; 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) { parseNovels(html: string) {
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
let tempNovel = {} as Plugin.NovelItem; let tempNovel = {} as Plugin.NovelItem;
@@ -154,7 +176,7 @@ class RanobesPlugin implements Plugin.PluginBase {
async popularNovels(page: number): Promise<Plugin.NovelItem[]> { async popularNovels(page: number): Promise<Plugin.NovelItem[]> {
const link = `${this.site}/${this.options.path}/page/${page}/`; 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); return this.parseNovels(body);
} }
@@ -162,8 +184,7 @@ class RanobesPlugin implements Plugin.PluginBase {
novelPath: string, novelPath: string,
): Promise<Plugin.SourceNovel & { totalPages: number }> { ): Promise<Plugin.SourceNovel & { totalPages: number }> {
const baseUrl = this.site; const baseUrl = this.site;
const result = await fetchApi(baseUrl + novelPath); const html = await this.safeFecth(baseUrl + novelPath);
const html = await result.text();
const novel: Plugin.SourceNovel & { totalPages: number } = { const novel: Plugin.SourceNovel & { totalPages: number } = {
path: novelPath, path: novelPath,
name: '', name: '',
@@ -330,9 +351,7 @@ class RanobesPlugin implements Plugin.PluginBase {
: '/' + novelPath.split('-').slice(1).join('-').split('.')[0]; : '/' + novelPath.split('-').slice(1).join('-').split('.')[0];
const firstUrl = const firstUrl =
this.site + '/chapters' + pagePath.replace(this.options.path + '/', ''); this.site + '/chapters' + pagePath.replace(this.options.path + '/', '');
const pageBody = await fetchApi(firstUrl + '/page/' + page).then(r => const pageBody = await this.safeFecth(firstUrl + '/page/' + page);
r.text(),
);
const baseUrl = this.site; const baseUrl = this.site;
let isScript = false; let isScript = false;
@@ -408,8 +427,7 @@ class RanobesPlugin implements Plugin.PluginBase {
} }
async parseChapter(chapterPath: string): Promise<string> { async parseChapter(chapterPath: string): Promise<string> {
const result = await fetchApi(this.site + chapterPath); const html = await this.safeFecth(this.site + chapterPath);
const html = await result.text();
const indexA = html.indexOf('<div class="text" id="arrticle">'); const indexA = html.indexOf('<div class="text" id="arrticle">');
const indexB = html.indexOf('<div class="category grey ellipses">', indexA); const indexB = html.indexOf('<div class="category grey ellipses">', indexA);
@@ -424,7 +442,7 @@ class RanobesPlugin implements Plugin.PluginBase {
): Promise<Plugin.NovelItem[]> { ): Promise<Plugin.NovelItem[]> {
let html; let html;
if (this.id === 'ranobes-ru') { 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: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
Referer: this.site + '/', Referer: this.site + '/',
@@ -436,10 +454,10 @@ class RanobesPlugin implements Plugin.PluginBase {
search_start: page.toString(), search_start: page.toString(),
story: searchTerm, story: searchTerm,
}).toString(), }).toString(),
}).then(res => res.text()); });
} else { } else {
const link = `${this.site}/search/${searchTerm}/page/${page}`; 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); return this.parseNovels(html);
} }
+30 -11
View File
@@ -9,9 +9,31 @@ class Foxteller implements Plugin.PluginBase {
id = 'foxteller'; id = 'foxteller';
name = 'Foxteller'; name = 'Foxteller';
site = 'https://www.foxteller.com'; site = 'https://www.foxteller.com';
version = '1.0.1'; version = '1.0.2';
icon = 'src/en/foxteller/icon.png'; 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( async popularNovels(
pageNo: number, pageNo: number,
{ filters }: Plugin.PopularNovelsOptions<typeof this.filters>, { filters }: Plugin.PopularNovelsOptions<typeof this.filters>,
@@ -19,7 +41,7 @@ class Foxteller implements Plugin.PluginBase {
const url = const url =
this.site + '/library?sort=' + filters?.order?.value || 'popularity'; 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 novels: Plugin.NovelItem[] = [];
const div = body.match(/<div class="col-md-6">([\s\S]*?)<\/div>/g) || []; 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> { async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
const body = await fetchApi(this.resolveUrl(novelPath)).then(res => const body = await this.safeFecth(this.resolveUrl(novelPath));
res.text(),
);
const novel: Plugin.SourceNovel = { const novel: Plugin.SourceNovel = {
path: novelPath, path: novelPath,
name: '', name: '',
@@ -189,10 +209,9 @@ class Foxteller implements Plugin.PluginBase {
} }
async parseChapter(chapterPath: string): Promise<string> { async parseChapter(chapterPath: string): Promise<string> {
const res = await fetchApi(this.resolveUrl(chapterPath)); const res = await this.safeFecth(this.resolveUrl(chapterPath));
const body = await res.text();
const novelID = chapterPath.split('/')[0]; 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'); 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', 'Accept-Language': 'ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3',
'Content-Type': 'application/json;charset=utf-8', 'Content-Type': 'application/json;charset=utf-8',
}, },
Referer: res.url, Referer: this.resolveUrl(chapterPath),
body: JSON.stringify({ 'x1': novelID, 'x2': chapterID }), body: JSON.stringify({ 'x1': novelID, 'x2': chapterID }),
}).then(res => res.json()); }).then(res => res.json());
@@ -234,7 +253,7 @@ class Foxteller implements Plugin.PluginBase {
} }
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> { async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
const body = await fetchApi(this.site + '/search', { const body = await this.safeFecth(this.site + '/search', {
method: 'post', method: 'post',
headers: { headers: {
Accept: 'application/json, text/plain, */*', Accept: 'application/json, text/plain, */*',
@@ -243,7 +262,7 @@ class Foxteller implements Plugin.PluginBase {
}, },
Referer: this.site, Referer: this.site,
body: JSON.stringify({ query: searchTerm }), body: JSON.stringify({ query: searchTerm }),
}).then(res => res.text()); });
const novels: Plugin.NovelItem[] = []; const novels: Plugin.NovelItem[] = [];
const items = body.match(/<a.*>([\s\S]*?)<\/a>/g) || []; const items = body.match(/<a.*>([\s\S]*?)<\/a>/g) || [];
+54 -6
View File
@@ -18,7 +18,7 @@ class RLIB implements Plugin.PluginBase {
name = 'RanobeLib'; name = 'RanobeLib';
site = 'https://ranobelib.me'; site = 'https://ranobelib.me';
apiSite = 'https://api.mangalib.me/api/manga/'; apiSite = 'https://api.mangalib.me/api/manga/';
version = '2.1.0'; version = '2.1.1';
icon = 'src/ru/ranobelib/icon.png'; icon = 'src/ru/ranobelib/icon.png';
webStorageUtilized = true; webStorageUtilized = true;
@@ -126,10 +126,10 @@ class RLIB implements Plugin.PluginBase {
novel.genres = genres.join(', '); novel.genres = genres.join(', ');
} }
const branch_id: Record<number, string> = {}; const branch_name: Record<number, string> = {};
if (data.teams.length) { if (data.teams.length) {
data.teams.forEach( 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[] = []; const chapters: Plugin.ChapterItem[] = [];
chaptersJSON.data.forEach(chapter => chaptersJSON.data.forEach(chapter =>
chapter.branches.forEach(({ branch_id, created_at }) =>
chapters.push({ chapters.push({
name: name:
'Том ' + 'Том ' +
@@ -158,13 +159,24 @@ class RLIB implements Plugin.PluginBase {
'/' + '/' +
chapter.number + chapter.number +
'/' + '/' +
(chapter.branches[0]?.branch_id || ''), (branch_id || ''),
releaseTime: dayjs(chapter.branches[0].created_at).format('LLL'), releaseTime: dayjs(created_at).format('LLL'),
chapterNumber: chapter.index, 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; novel.chapters = chapters;
} }
@@ -509,6 +521,42 @@ function jsonToHtml(json: HTML[], images, html = '') {
(element.content ? jsonToHtml(element.content, images) : '<br>') + (element.content ? jsonToHtml(element.content, images) : '<br>') +
'</p>'; '</p>';
break; 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': case 'heading':
html += html +=
'<h2>' + '<h2>' +