153 lines
4.8 KiB
JavaScript
153 lines
4.8 KiB
JavaScript
class novelfire {
|
|
constructor(fetchPath, cheerioPath, browser) {
|
|
this.browser = browser;
|
|
this.fetch = require(fetchPath);
|
|
this.cheerio = require(cheerioPath);
|
|
this.baseUrl = "https://novelfire.net";
|
|
this.type = "book-board";
|
|
}
|
|
|
|
async fetchSearchResult(query = "", page = 1) {
|
|
let html;
|
|
|
|
if (query.trim() === "") {
|
|
const res = await this.fetch(`${this.baseUrl}/home`);
|
|
html = await res.text();
|
|
} else {
|
|
const res = await this.fetch(
|
|
`${this.baseUrl}/ajax/searchLive?inputContent=${encodeURIComponent(query)}`
|
|
);
|
|
const data = await res.json();
|
|
html = data.html;
|
|
}
|
|
|
|
const $ = this.cheerio.load(html);
|
|
const results = [];
|
|
|
|
$(".novel-item").each((_, el) => {
|
|
const a = $(el).find("a");
|
|
const href = a.attr("href") || "";
|
|
const title = $(el).find(".novel-title").text().trim();
|
|
|
|
const img = $(el).find("img");
|
|
const image = img.attr("data-src") || img.attr("src") || "";
|
|
|
|
const id = href.replace("https://novelfire.net/book/", "").replace(/\/$/, "");
|
|
|
|
results.push({
|
|
id,
|
|
title,
|
|
image,
|
|
sampleImageUrl: image,
|
|
tags: [],
|
|
type: "book"
|
|
});
|
|
});
|
|
|
|
return {
|
|
results,
|
|
hasNextPage: false,
|
|
page
|
|
};
|
|
}
|
|
|
|
async findChapters(bookId) {
|
|
const url = `https://novelfire.net/book/${bookId}/chapter-1`;
|
|
|
|
const options = await this.browser.scrape(
|
|
url,
|
|
async () => {
|
|
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
|
|
|
const select = document.querySelector('.chapindex');
|
|
if (!select) return [];
|
|
|
|
select.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }));
|
|
select.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
|
|
for (let i = 0; i < 20; i++) {
|
|
if (document.querySelectorAll('.select2-results__option').length > 0) break;
|
|
await sleep(300);
|
|
}
|
|
|
|
return [...select.querySelectorAll('option')].map(opt => ({
|
|
id: opt.value,
|
|
title: opt.textContent.trim(),
|
|
chapter: Number(opt.dataset.n_sort || 0),
|
|
}));
|
|
},
|
|
{
|
|
waitSelector: '.chapindex',
|
|
timeout: 10000
|
|
}
|
|
);
|
|
|
|
return options.map(o => ({
|
|
id: `https://novelfire.net/book/${bookId}/chapter-${o.chapter}`,
|
|
title: o.title,
|
|
chapter: o.chapter,
|
|
language: "en"
|
|
}));
|
|
}
|
|
|
|
async findChapterPages(chapterId) {
|
|
const res = await this.fetch(chapterId);
|
|
const html = await res.text();
|
|
|
|
const $ = this.cheerio.load(html);
|
|
const contentDiv = $("#content");
|
|
|
|
if (!contentDiv || contentDiv.length === 0) {
|
|
return [{
|
|
type: "text",
|
|
content: "<p>Error: content not found</p>",
|
|
index: 0
|
|
}];
|
|
}
|
|
|
|
contentDiv.find("script").remove();
|
|
contentDiv.find("ins").remove();
|
|
contentDiv.find("[id^='pf-']").remove();
|
|
contentDiv.find(".ads").remove();
|
|
contentDiv.find(".adsbygoogle").remove();
|
|
contentDiv.find("div[style*='text-align:center']").remove();
|
|
contentDiv.find("div[align='center']").remove();
|
|
contentDiv.find(".nf-ads").remove();
|
|
contentDiv.find("nfne597").remove();
|
|
|
|
const paragraphs = contentDiv.find("p");
|
|
let cleanHtml = "";
|
|
|
|
paragraphs.each((_, el) => {
|
|
const p = $(el);
|
|
|
|
let text = p.text() || "";
|
|
|
|
text = text.replace(/△▼△▼△▼△/g, "");
|
|
text = text.replace(/[※]+/g, "");
|
|
text = text.replace(/\s{2,}/g, " ");
|
|
|
|
const htmlP = p.html()?.trim() || "";
|
|
const isEmpty = htmlP === "" || htmlP === " " || text.trim() === "";
|
|
|
|
const isAd = text.includes("Remove Ads") || text.includes("Buy no ads") || text.includes("novelfire");
|
|
|
|
if (!isEmpty && !isAd) {
|
|
if (p.text() !== text) p.text(text);
|
|
cleanHtml += $.html(p);
|
|
}
|
|
});
|
|
|
|
if (!cleanHtml.trim()) { cleanHtml = contentDiv.html(); }
|
|
|
|
return [
|
|
{
|
|
type: "text",
|
|
content: cleanHtml.trim(),
|
|
index: 0
|
|
}
|
|
];
|
|
}
|
|
}
|
|
|
|
module.exports = { novelupdates: novelfire }; |