fix(rewayatfans): Improve Novel Listing and Chapter Extraction
This commit is contained in:
@@ -3,18 +3,19 @@ import { fetchApi } from '@libs/fetch';
|
|||||||
import { Plugin } from '@/types/plugin';
|
import { Plugin } from '@/types/plugin';
|
||||||
|
|
||||||
type WPPage = {
|
type WPPage = {
|
||||||
id: number;
|
|
||||||
title: { rendered: string };
|
title: { rendered: string };
|
||||||
slug: string;
|
slug: string;
|
||||||
link: string;
|
|
||||||
content: { rendered: string };
|
|
||||||
date: string;
|
date: string;
|
||||||
|
featured_media: number;
|
||||||
|
_embedded?: {
|
||||||
|
'wp:featuredmedia'?: Array<{ source_url: string }>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
class RewayatFans implements Plugin.PluginBase {
|
class RewayatFans implements Plugin.PluginBase {
|
||||||
id = 'rewayatfans';
|
id = 'rewayatfans';
|
||||||
name = 'روايات فانز';
|
name = 'روايات فانز';
|
||||||
version = '3.0.0';
|
version = '4.2.0';
|
||||||
icon = 'src/ar/rewayatfans/icon.png';
|
icon = 'src/ar/rewayatfans/icon.png';
|
||||||
site = 'https://rewayatfans.com/';
|
site = 'https://rewayatfans.com/';
|
||||||
|
|
||||||
@@ -30,58 +31,31 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
return res.text();
|
return res.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getCover(page: WPPage): string {
|
||||||
|
return page._embedded?.['wp:featuredmedia']?.[0]?.source_url || '';
|
||||||
|
}
|
||||||
|
|
||||||
async popularNovels(
|
async popularNovels(
|
||||||
page: number,
|
page: number,
|
||||||
{ showLatestNovels }: Plugin.PopularNovelsOptions,
|
{ showLatestNovels }: Plugin.PopularNovelsOptions,
|
||||||
): Promise<Plugin.NovelItem[]> {
|
): Promise<Plugin.NovelItem[]> {
|
||||||
if (showLatestNovels) {
|
const pages = await this.fetchJson<WPPage[]>(
|
||||||
const pages = await this.fetchJson<WPPage[]>(
|
`${this.site}wp-json/wp/v2/pages?per_page=20&page=${page}&orderby=date&order=desc&_embed`,
|
||||||
`${this.site}wp-json/wp/v2/pages?per_page=20&page=${page}&orderby=date&order=desc&_fields=slug,title`,
|
);
|
||||||
);
|
|
||||||
return pages.map(p => ({
|
|
||||||
name: this.extractNovelName(p.title.rendered),
|
|
||||||
path: p.slug,
|
|
||||||
cover: '',
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
const allNovels = await this.getAllNovels();
|
|
||||||
const pageSize = 20;
|
|
||||||
const start = (page - 1) * pageSize;
|
|
||||||
return allNovels.slice(start, start + pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async getAllNovels(): Promise<Plugin.NovelItem[]> {
|
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const novels: Plugin.NovelItem[] = [];
|
const novels: Plugin.NovelItem[] = [];
|
||||||
|
|
||||||
let pg = 1;
|
for (const p of pages) {
|
||||||
let hasMore = true;
|
const novelName = this.extractNovelName(p.title.rendered);
|
||||||
|
if (novelName && !seen.has(novelName)) {
|
||||||
while (hasMore) {
|
seen.add(novelName);
|
||||||
const pages = await this.fetchJson<WPPage[]>(
|
novels.push({
|
||||||
`${this.site}wp-json/wp/v2/pages?per_page=100&page=${pg}&_fields=slug,title`,
|
name: novelName,
|
||||||
);
|
path: p.slug,
|
||||||
|
cover: this.getCover(p),
|
||||||
if (pages.length === 0) {
|
});
|
||||||
hasMore = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const page of pages) {
|
|
||||||
const novelName = this.extractNovelName(page.title.rendered);
|
|
||||||
if (novelName && !seen.has(novelName)) {
|
|
||||||
seen.add(novelName);
|
|
||||||
novels.push({
|
|
||||||
name: novelName,
|
|
||||||
path: page.slug,
|
|
||||||
cover: '',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pages.length < 100) hasMore = false;
|
|
||||||
pg++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return novels;
|
return novels;
|
||||||
@@ -95,16 +69,19 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const slugBase = novelPath.replace(/\/$/, '').split('/').pop() || novelPath;
|
const slugBase = novelPath.replace(/\/$/, '').split('/').pop() || novelPath;
|
||||||
const searchTerm = slugBase
|
const novelPrefix = slugBase.replace(/-\d+$/, '');
|
||||||
.replace(/-\d+$/, '')
|
const searchName = novelPrefix.replace(/-/g, ' ');
|
||||||
.replace(/-/g, ' ');
|
|
||||||
|
const normalize = (s: string) =>
|
||||||
|
s.toLowerCase().replace(/[^a-z0-9\s]/g, '').replace(/\s+/g, ' ').trim();
|
||||||
|
const normalizedSearch = normalize(searchName);
|
||||||
|
|
||||||
let pg = 1;
|
let pg = 1;
|
||||||
let hasMore = true;
|
let hasMore = true;
|
||||||
|
|
||||||
while (hasMore) {
|
while (hasMore) {
|
||||||
const pages = await this.fetchJson<WPPage[]>(
|
const pages = await this.fetchJson<WPPage[]>(
|
||||||
`${this.site}wp-json/wp/v2/pages?search=${encodeURIComponent(searchTerm)}&per_page=100&page=${pg}&_fields=slug,title,date`,
|
`${this.site}wp-json/wp/v2/pages?search=${encodeURIComponent(searchName)}&per_page=100&page=${pg}&_fields=slug,title,date`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pages.length === 0) {
|
if (pages.length === 0) {
|
||||||
@@ -112,20 +89,23 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const page of pages) {
|
for (const p of pages) {
|
||||||
const postSlug = page.slug;
|
const normalizedTitle = normalize(p.title.rendered);
|
||||||
if (postSlug.startsWith(slugBase.replace(/-\d+$/, ''))) {
|
if (
|
||||||
|
p.slug.startsWith(novelPrefix) ||
|
||||||
|
normalizedTitle.startsWith(normalizedSearch)
|
||||||
|
) {
|
||||||
if (!novel.name) {
|
if (!novel.name) {
|
||||||
novel.name = this.extractNovelName(page.title.rendered);
|
novel.name = this.extractNovelName(p.title.rendered);
|
||||||
}
|
}
|
||||||
const numMatch = postSlug.match(/(\d+)$/);
|
const numMatch = p.title.rendered.match(/(\d+)\s*$/);
|
||||||
const chapterNum = numMatch ? parseInt(numMatch[1], 10) : 0;
|
const chapterNum = numMatch ? parseInt(numMatch[1], 10) : 0;
|
||||||
|
|
||||||
novel.chapters!.push({
|
novel.chapters!.push({
|
||||||
name: page.title.rendered,
|
name: p.title.rendered,
|
||||||
path: postSlug,
|
path: p.slug,
|
||||||
chapterNumber: chapterNum,
|
chapterNumber: chapterNum,
|
||||||
releaseTime: page.date,
|
releaseTime: p.date,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,11 +114,12 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
pg++;
|
pg++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (novel.chapters!.length > 0) {
|
novel.chapters!.sort(
|
||||||
novel.chapters!.sort((a, b) => (a.chapterNumber || 0) - (b.chapterNumber || 0));
|
(a, b) => (a.chapterNumber || 0) - (b.chapterNumber || 0),
|
||||||
if (!novel.name && novel.chapters!.length > 0) {
|
);
|
||||||
novel.name = this.extractNovelName(novel.chapters![0].name);
|
|
||||||
}
|
if (!novel.name && novel.chapters!.length > 0) {
|
||||||
|
novel.name = this.extractNovelName(novel.chapters![0].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return novel;
|
return novel;
|
||||||
@@ -150,8 +131,8 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const arr = Array.isArray(pages) ? pages : [pages];
|
const arr = Array.isArray(pages) ? pages : [pages];
|
||||||
if (arr.length > 0 && arr[0].content?.rendered) {
|
if (arr.length > 0 && (arr[0] as any).content?.rendered) {
|
||||||
const $ = parseHTML(arr[0].content.rendered);
|
const $ = parseHTML((arr[0] as any).content.rendered);
|
||||||
$('script, style, .sharedaddy, .jp-relatedposts, .wp-block-spacer').remove();
|
$('script, style, .sharedaddy, .jp-relatedposts, .wp-block-spacer').remove();
|
||||||
return $.html();
|
return $.html();
|
||||||
}
|
}
|
||||||
@@ -168,20 +149,20 @@ class RewayatFans implements Plugin.PluginBase {
|
|||||||
page: number,
|
page: number,
|
||||||
): Promise<Plugin.NovelItem[]> {
|
): Promise<Plugin.NovelItem[]> {
|
||||||
const pages = await this.fetchJson<WPPage[]>(
|
const pages = await this.fetchJson<WPPage[]>(
|
||||||
`${this.site}wp-json/wp/v2/pages?search=${encodeURIComponent(searchTerm)}&per_page=20&page=${page}&_fields=slug,title`,
|
`${this.site}wp-json/wp/v2/pages?search=${encodeURIComponent(searchTerm)}&per_page=20&page=${page}&_embed`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const novels: Plugin.NovelItem[] = [];
|
const novels: Plugin.NovelItem[] = [];
|
||||||
|
|
||||||
for (const page of pages) {
|
for (const p of pages) {
|
||||||
const novelName = this.extractNovelName(page.title.rendered);
|
const novelName = this.extractNovelName(p.title.rendered);
|
||||||
if (novelName && !seen.has(novelName)) {
|
if (novelName && !seen.has(novelName)) {
|
||||||
seen.add(novelName);
|
seen.add(novelName);
|
||||||
novels.push({
|
novels.push({
|
||||||
name: novelName,
|
name: novelName,
|
||||||
path: page.slug,
|
path: p.slug,
|
||||||
cover: '',
|
cover: this.getCover(p),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user