Files
WaifuBoard-Extensions/novelfire.js
2025-11-24 01:50:49 +01:00

155 lines
4.9 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 {
chapters: 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 === "&nbsp;" || 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 };