fix(rewayatfans): Improve Novel Listing and Chapter Extraction

This commit is contained in:
hamedhani1998
2026-07-22 05:38:30 +03:00
committed by GitHub
parent 1d462b0351
commit be39827275
+52 -71
View File
@@ -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),
}); });
} }
} }