Change RoyalRoad regex, fix Faqwiki (#849)
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { CheerioAPI, load as parseHTML } from "cheerio";
|
||||
import { fetchApi, fetchFile } from "@libs/fetch";
|
||||
import { FilterTypes, Filters } from "@libs/filterInputs";
|
||||
import { Plugin } from "@typings/plugin";
|
||||
import { defaultCover } from "@libs/defaultCover";
|
||||
|
||||
@@ -8,7 +7,7 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
id = "DDL.com";
|
||||
name = "Divine Dao Library";
|
||||
site = "https://www.divinedaolibrary.com/";
|
||||
version = "1.0.0";
|
||||
version = "1.0.1";
|
||||
icon = "src/en/divinedaolibrary/icon.png";
|
||||
filters?: undefined;
|
||||
|
||||
@@ -20,7 +19,7 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
.each((i,el) => {
|
||||
const novelName = loadedCheerio(el).find("a").text();
|
||||
const novelCover = defaultCover;
|
||||
const novelUrl = loadedCheerio(el).find(" a").attr("href");
|
||||
const novelUrl = loadedCheerio(el).find("a").attr("href");
|
||||
|
||||
if (!novelUrl) return;
|
||||
|
||||
@@ -135,4 +134,5 @@ class DDLPlugin implements Plugin.PluginBase {
|
||||
return await fetchFile(url);
|
||||
}
|
||||
}
|
||||
|
||||
export default new DDLPlugin();
|
||||
+95
-111
@@ -1,131 +1,115 @@
|
||||
import { Plugin } from "@typings/plugin";
|
||||
import { fetchApi, fetchFile } from "@libs/fetch";
|
||||
import { NovelStatus } from "@libs/novelStatus";
|
||||
import { load as parseHTML } from "cheerio";
|
||||
import { CheerioAPI, load as parseHTML } from "cheerio";
|
||||
|
||||
class FaqWikiUs implements Plugin.PluginBase {
|
||||
id = "FWK.US";
|
||||
name = "Faq Wiki";
|
||||
site = "https://faqwiki.us/";
|
||||
version = "1.0.0";
|
||||
icon = "src/en/faqwikius/icon.png";
|
||||
id = "FWK.US";
|
||||
name = "Faq Wiki";
|
||||
site = "https://faqwiki.us/";
|
||||
version = "1.1.0";
|
||||
icon = "src/en/faqwikius/icon.png";
|
||||
|
||||
async popularNovels(
|
||||
page: number,
|
||||
{ showLatestNovels }: Plugin.PopularNovelsOptions,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
|
||||
const body = await fetchApi(this.site).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novels: Plugin.NovelItem[] = loadedCheerio(".wp-block-table > table > tbody > tr")
|
||||
.map((index, element) => {
|
||||
const name = loadedCheerio(element).find('a').text().replace(/–\s+Chapter\s+List\s+–.*$/i,'');
|
||||
let cover = loadedCheerio(element).find("img").attr("data-ezsrc");
|
||||
|
||||
// Remove the appended query string
|
||||
if (cover) {
|
||||
cover = cover.replace(/\?ezimgfmt=.*$/, ''); // Regular expression magic!
|
||||
}
|
||||
|
||||
const path = "" + loadedCheerio(element).find("a").attr("href")?.toString().replace(this.site, "").trim();
|
||||
|
||||
|
||||
return { name, cover, path };
|
||||
})
|
||||
.get()
|
||||
.filter((novel) => novel.name && novel.path);
|
||||
|
||||
return novels;
|
||||
}
|
||||
|
||||
async parseNovel(path: string): Promise<Plugin.SourceNovel> {
|
||||
const body = await fetchApi(this.site + path).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path,
|
||||
name: ""
|
||||
};
|
||||
novel.name = loadedCheerio(".entry-title").text().replace("Novel – All Chapters", "").trim();
|
||||
|
||||
let cover = loadedCheerio(".wp-block-image").find("img").attr("data-ezsrc");
|
||||
parseNovels(loadedCheerio:CheerioAPI, searchTerm?: string) {
|
||||
let novels: Plugin.NovelItem[] = [];
|
||||
|
||||
loadedCheerio("figure.wp-block-image").each((index, element) => {
|
||||
const name = loadedCheerio(element).text();
|
||||
let cover = loadedCheerio(element).find("img").attr("data-ezsrc");
|
||||
|
||||
// Remove the appended query string
|
||||
if (cover) {
|
||||
cover = cover.replace(/\?ezimgfmt=.*$/, ''); // Regular expression magic!
|
||||
cover = cover.replace(/\?ezimgfmt=.*$/, ''); // Regular expression magic!
|
||||
}
|
||||
novel.cover = cover;
|
||||
|
||||
novel.summary = loadedCheerio(".book-review-block__meta-item-value").text().trim();
|
||||
const path = loadedCheerio(element).find("a").attr("href")?.slice(this.site.length);
|
||||
if (!path) return;
|
||||
|
||||
const chapters: Plugin.ChapterItem[] = loadedCheerio(".lcp_catlist > li > a")
|
||||
.map((chapterIndex, element) => ({
|
||||
name: loadedCheerio(element).text().replace(novel.name + "", "").replace("Novel" + "", "").trim(),
|
||||
path: ""+loadedCheerio(element).attr("href")?.toString().replace(this.site, "").trim(),
|
||||
releaseTime: null,
|
||||
chapterNumber: chapterIndex + 1,
|
||||
}))
|
||||
.get();
|
||||
novels.push({ name, cover, path });
|
||||
})
|
||||
|
||||
novel.chapters = chapters;
|
||||
return novel;
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const body = await fetchApi(this.site + chapterPath).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
loadedCheerio("span").remove();
|
||||
|
||||
const chapterParagraphs = loadedCheerio(".entry-content p");
|
||||
|
||||
let chapterContent; // Variable to store the result
|
||||
|
||||
if (chapterParagraphs.length < 5) { //some chapter in this site store their whole text in 1-4 <p>,
|
||||
chapterContent = chapterParagraphs.map((index, element) => {
|
||||
const text = loadedCheerio(element).html()
|
||||
return text;
|
||||
}).get().join('\n\n');
|
||||
}
|
||||
|
||||
else {
|
||||
// Multiple paragraphs case
|
||||
chapterContent = chapterParagraphs.map((index, element) => {
|
||||
const text = loadedCheerio(element).text().trim();
|
||||
return `<p>${text}</p>`;
|
||||
}).get().join('\n\n');
|
||||
}
|
||||
|
||||
return chapterContent;
|
||||
}
|
||||
|
||||
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const body = await fetchApi(this.site).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novels: Plugin.NovelItem[] = loadedCheerio(".wp-block-table > table > tbody > tr")
|
||||
.map((index, element) => {
|
||||
const name = loadedCheerio(element).find('a').text().replace(/–\s+Chapter\s+List\s+–.*$/i,'');
|
||||
let cover = loadedCheerio(element).find("img").attr("data-ezsrc");
|
||||
|
||||
// Remove the appended query string
|
||||
if (cover) {
|
||||
cover = cover.replace(/\?ezimgfmt=.*$/, ''); // Regular expression magic!
|
||||
if (searchTerm) {
|
||||
novels = novels.filter((novel) =>
|
||||
novel.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
const path = "" + loadedCheerio(element).find("a").attr("href")?.toString().replace(this.site, "").trim();
|
||||
return novels;
|
||||
}
|
||||
|
||||
return { name, cover, path };
|
||||
})
|
||||
.get().filter((novel) => novel.name && novel.path);
|
||||
const normalizedQuery = searchTerm.toLowerCase();
|
||||
return novels.filter(novel => novel.name.toLowerCase().includes(normalizedQuery));
|
||||
async popularNovels(
|
||||
page: number,
|
||||
{ showLatestNovels }: Plugin.PopularNovelsOptions,
|
||||
): Promise<Plugin.NovelItem[]> {
|
||||
|
||||
const body = await fetchApi(this.site).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
return novels;
|
||||
}
|
||||
return this.parseNovels(loadedCheerio);
|
||||
}
|
||||
|
||||
fetchImage = fetchFile;
|
||||
async parseNovel(path: string): Promise<Plugin.SourceNovel> {
|
||||
const body = await fetchApi(this.site + path).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
const novel: Plugin.SourceNovel = {
|
||||
path,
|
||||
name: ""
|
||||
};
|
||||
|
||||
novel.name = loadedCheerio(".entry-title").text().replace("Novel – All Chapters", "").trim();
|
||||
|
||||
novel.cover = loadedCheerio(".wp-block-image").find("img").attr("src");
|
||||
|
||||
novel.summary = loadedCheerio(".book-review-block__meta-item-value").text().trim();
|
||||
|
||||
const chapters: Plugin.ChapterItem[] = loadedCheerio(".lcp_catlist > li > a")
|
||||
.map((chapterIndex, element) => ({
|
||||
name: loadedCheerio(element).text().replace(novel.name + "", "").replace("Novel" + "", "").trim(),
|
||||
path: ""+loadedCheerio(element).attr("href")?.slice(this.site.length),
|
||||
chapterNumber: chapterIndex + 1,
|
||||
}))
|
||||
.get();
|
||||
|
||||
novel.chapters = chapters;
|
||||
return novel;
|
||||
}
|
||||
|
||||
async parseChapter(chapterPath: string): Promise<string> {
|
||||
const body = await fetchApi(this.site + chapterPath).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
loadedCheerio("span").remove();
|
||||
|
||||
const chapterParagraphs = loadedCheerio(".entry-content p");
|
||||
|
||||
let chapterContent; // Variable to store the result
|
||||
|
||||
if (chapterParagraphs.length < 5) { //some chapter in this site store their whole text in 1-4 <p>,
|
||||
chapterContent = chapterParagraphs.map((index, element) => {
|
||||
const text = loadedCheerio(element).html()
|
||||
return text;
|
||||
}).get().join('\n\n');
|
||||
}
|
||||
|
||||
else {
|
||||
// Multiple paragraphs case
|
||||
chapterContent = chapterParagraphs.map((index, element) => {
|
||||
const text = loadedCheerio(element).text().trim();
|
||||
return `<p>${text}</p>`;
|
||||
}).get().join('\n\n');
|
||||
}
|
||||
|
||||
return chapterContent;
|
||||
}
|
||||
|
||||
|
||||
async searchNovels(searchTerm: string): Promise<Plugin.NovelItem[]> {
|
||||
const body = await fetchApi(this.site).then((res) => res.text());
|
||||
const loadedCheerio = parseHTML(body);
|
||||
|
||||
return this.parseNovels(loadedCheerio, searchTerm);
|
||||
}
|
||||
|
||||
fetchImage = fetchFile;
|
||||
}
|
||||
|
||||
export default new FaqWikiUs();
|
||||
|
||||
@@ -8,7 +8,7 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
name = "LnMTL";
|
||||
icon = "src/en/lnmtl/icon.png";
|
||||
site = "https://lnmtl.com/";
|
||||
version = "1.0.0";
|
||||
version = "1.0.1";
|
||||
|
||||
async sleep (ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
@@ -112,12 +112,6 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
)[+page-1];
|
||||
|
||||
const chapter: Plugin.ChapterItem[] = [];
|
||||
interface ChapterEntry {
|
||||
number: number;
|
||||
title: string;
|
||||
slug: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
await this.sleep(1000);
|
||||
const volumeData = await fetchApi(
|
||||
@@ -243,4 +237,11 @@ class LnMTLPlugin implements Plugin.PagePlugin {
|
||||
} satisfies Filters;
|
||||
}
|
||||
|
||||
export default new LnMTLPlugin();
|
||||
export default new LnMTLPlugin();
|
||||
|
||||
interface ChapterEntry {
|
||||
number: number;
|
||||
title: string;
|
||||
slug: string;
|
||||
created_at: string;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CheerioAPI, load, load as parseHTML } from "cheerio";
|
||||
import { CheerioAPI, load as parseHTML } from "cheerio";
|
||||
import { fetchApi, fetchFile } from "@libs/fetch";
|
||||
import { Plugin } from "@typings/plugin";
|
||||
import { Filters, FilterTypes } from "@libs/filterInputs";
|
||||
@@ -6,7 +6,7 @@ import { Filters, FilterTypes } from "@libs/filterInputs";
|
||||
class RoyalRoad implements Plugin.PluginBase {
|
||||
id = "royalroad";
|
||||
name = "Royal Road";
|
||||
version = "1.0.0";
|
||||
version = "1.0.1";
|
||||
icon = "src/en/royalroad/icon.png";
|
||||
site = "https://www.royalroad.com/";
|
||||
|
||||
@@ -71,26 +71,28 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
.toArray()
|
||||
.join(",");
|
||||
|
||||
const chapterlisting = JSON.parse(
|
||||
loadedCheerio('script:contains("window.chapters")')
|
||||
.html()
|
||||
?.match(/window.chapters = \[(.*?)\]/)![0]
|
||||
?.replace("window.chapters = ", "") || ""
|
||||
const chapterJson = JSON.parse(loadedCheerio('script:contains("window.chapters")')
|
||||
.html()
|
||||
?.match(/window.chapters = (.+])(?=;)/)![1] || "");
|
||||
|
||||
const volumeJson = JSON.parse(loadedCheerio('script:contains("window.chapters")')
|
||||
.html()
|
||||
?.match(/window.volumes = (.+])(?=;)/)![1] || "");
|
||||
|
||||
const chapter : Plugin.ChapterItem[] = chapterJson.map(
|
||||
(chapter: ChapterEntry) => {
|
||||
const matchingVolume = volumeJson.find(
|
||||
(volume: VolumeEntry) => volume.id === chapter.volumeId);
|
||||
return {
|
||||
name: chapter.title,
|
||||
path: chapter.url.slice(1),
|
||||
releaseTime: chapter.date,
|
||||
chapterNumber: chapter?.order,
|
||||
page: matchingVolume ? matchingVolume.title : null,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
interface ChapterEntry {
|
||||
title: string;
|
||||
date: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const chapter : Plugin.ChapterItem[] = chapterlisting.map(
|
||||
(chapter: ChapterEntry) => ({
|
||||
name: chapter.title,
|
||||
path: chapter.url.slice(1),
|
||||
releaseTime: chapter.date,
|
||||
}))
|
||||
|
||||
novel.chapters = chapter;
|
||||
return novel;
|
||||
}
|
||||
@@ -164,4 +166,20 @@ class RoyalRoad implements Plugin.PluginBase {
|
||||
} satisfies Filters;
|
||||
}
|
||||
|
||||
export default new RoyalRoad();
|
||||
export default new RoyalRoad();
|
||||
|
||||
interface ChapterEntry {
|
||||
id: number;
|
||||
volumeId: number;
|
||||
title: string;
|
||||
date: string;
|
||||
order: number;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface VolumeEntry {
|
||||
id: number;
|
||||
title: string;
|
||||
cover: string;
|
||||
order: number;
|
||||
}
|
||||
Reference in New Issue
Block a user