Files
WaifuBoard-Extensions/novelfire.js

137 lines
4.2 KiB
JavaScript

class NovelFire {
constructor() {
this.baseUrl = "https://novelfire.net";
this.type = "book-board";
this.mediaType = "ln";
}
async search(queryObj) {
const query = queryObj.query;
const res = await fetch(
`${this.baseUrl}/ajax/searchLive?inputContent=${encodeURIComponent(query)}`,
{ headers: { "accept": "application/json" } }
);
const data = await res.json();
if (!data.data) return [];
return data.data.map(item => ({
id: item.slug,
title: item.title,
image: `https://novelfire.net/${item.image}`,
rating: item.rank ?? null,
type: "book"
}));
}
async getMetadata(id) {
const url = `https://novelfire.net/book/${id}`;
const html = await (await fetch(url)).text();
const $ = this.cheerio.load(html);
const title = $('h1[itemprop="name"]').first().text().trim() || null;
const summary = $('meta[itemprop="description"]').attr('content') || null;
const image =
$('figure.cover img').attr('src') ||
$('img.cover').attr('src') ||
$('img[src*="server-"]').attr('src') ||
null;
const genres = $('.categories a.property-item')
.map((_, el) => $(el).attr('title') || $(el).text().trim())
.get();
let chapters = null;
const latest = $('.chapter-latest-container .latest').text();
if (latest) {
const m = latest.match(/Chapter\s+(\d+)/i);
if (m) chapters = Number(m[1]);
}
let status = 'unknown';
const statusClass = $('strong.ongoing, strong.completed').attr('class');
if (statusClass) {
status = statusClass.toLowerCase();
}
return {
id,
title,
format: 'Light Novel',
score: 0,
genres,
status,
published: '???',
summary,
chapters,
image
};
}
async findChapters(bookId) {
const url = `https://novelfire.net/book/${bookId}/chapters`;
const html = await (await fetch(url)).text();
const $ = this.cheerio.load(html);
let postId;
$("script").each((_, el) => {
const txt = $(el).html() || "";
const m = txt.match(/listChapterDataAjax\?post_id=(\d+)/);
if (m) postId = m[1];
});
if (!postId) throw new Error("post_id not found");
const params = new URLSearchParams({
post_id: postId,
draw: 1,
"columns[0][data]": "title",
"columns[0][orderable]": "false",
"columns[1][data]": "created_at",
"columns[1][orderable]": "true",
"order[0][column]": 1,
"order[0][dir]": "asc",
start: 0,
length: 1000
});
const res = await fetch(
`https://novelfire.net/listChapterDataAjax?${params}`,
{ headers: { "x-requested-with": "XMLHttpRequest" } }
);
const json = await res.json();
if (!json?.data) throw new Error("Invalid response");
return json.data.map((c, i) => ({
id: `https://novelfire.net/book/${bookId}/chapter-${c.n_sort}`,
title: c.title,
number: Number(c.n_sort),
release_date: c.created_at ?? null,
index: i,
language: "en"
}));
}
async findChapterPages(url) {
const html = await (await fetch(url)).text();
const $ = this.cheerio.load(html);
const $content = $("#content").clone();
$content.find("script, ins, .nf-ads, img, nfn2a74").remove();
$content.find("*").each((_, el) => {
$(el).removeAttr("id").removeAttr("class").removeAttr("style");
});
return $content.html()
.replace(/adsbygoogle/gi, "")
.replace(/novelfire/gi, "")
.trim();
}
}
module.exports = NovelFire;