From d2816bea9ba05bbd004bfe523b892bbc2be8d3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E5=8D=8E=E6=A2=81?= <642615676@qq.com> Date: Sun, 8 Sep 2024 16:48:03 +0800 Subject: [PATCH] Add bilinovel.com.js --- repo/bilinovel.com.js | 152 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 repo/bilinovel.com.js diff --git a/repo/bilinovel.com.js b/repo/bilinovel.com.js new file mode 100644 index 0000000..94936cb --- /dev/null +++ b/repo/bilinovel.com.js @@ -0,0 +1,152 @@ +// ==MiruExtension== +// @name 哔哩轻小说 +// @version v0.0.3 +// @author hualiang +// @lang zh +// @icon https://www.bilinovel.com/favicon.ico +// @license MIT +// @package bilinovel.com +// @type fikushon +// @webSite https://www.bilinovel.com +// ==/MiruExtension== +export default class extends Extension { + dict = { "“": "「", "”": "」", "‘": "『", "’": "』", "": "的", "": "一", "": "是", "": "了", "": "我", "": "不", "": "人", + "": "在", "": "他", "": "有", "": "这", "": "个", "": "上", "": "们", "": "来", "": "到", "": "时", "": "大", + "": "地", "": "为", "": "子", "": "中", "": "你", "": "说", "": "生", "": "国", "": "年", "": "着", "": "就", + "": "那", "": "和", "": "要", "": "她", "": "出", "": "也", "": "得", "": "里", "": "后", "": "自", "": "以", + "": "会", "": "家", "": "可", "": "下", "": "而", "": "过", "": "天", "": "去", "": "能", "": "对", "": "小", + "": "多", "": "然", "": "于", "": "心", "": "学", "": "么", "": "之", "": "都", "": "好", "": "看", "": "起", + "": "发", "": "当", "": "没", "": "成", "": "只", "": "如", "": "事", "": "把", "": "还", "": "用", "": "第", + "": "样", "": "道", "": "想", "": "作", "": "种", "": "开", "": "美", "": "乳", "": "阴", "": "液", "": "茎", + "": "欲", "": "呻", "": "肉", "": "交", "": "性", "": "胸", "": "私", "": "穴", "": "淫", "": "臀", "": "舔", + "": "射", "": "脱", "": "裸", "": "骚", "": "唇", " ": " ", "<": "<", ">": ">", "&": "&", "⋅": '·', + }; + + async load() { + this.querySelector = async (content, selector) => { + const res = await this.querySelectorAll(content, selector); + return res === null ? null : res[0]; + }; + this.text = (element) => { + return [...element.content.matchAll(/>([^<\n]+?) m[1].trim()).join(""); + }; + this.filter = (element) => { // 59392 + if (element.content.startsWith(" this.dict[c] || c); + }; + this.handle = async (url, count = 10) => { + try { + const response = await this.request(url, { headers: { "Accept-Language": "zh-cn", Accept: "*/*" } }); + const row = await this.querySelectorAll(response, "#acontentz > p, img"); + return row.map(this.filter); + } catch (error) { + if (count > 0) { + console.log(`Retry ${count} times: ${url}`); + await new Promise((resolve) => setTimeout(resolve, 1000)); + return this.handle(url, count - 1); + } else { + throw error; + } + } + }; + } + + async latest(page) { + const res = await this.request(`/top/lastupdate/${page}.html`); + const list = await this.querySelectorAll(res, ".book-li > a"); + const tasks = list.map(async (e) => { + const img = await this.querySelector(e.content, "img"); + const cover = await img.getAttributeText("data-src"); + const title = await img.getAttributeText("alt"); + const update = this.text(await this.querySelector(e.content, ".book-author")); + const url = `${e.content.match(/href="(.*?)"/)[1]}|${title}|${cover}`; + return { title, url, cover, update }; + }); + return await Promise.all(tasks); + } + + async search(kw, page) { + const res = await this.request(`/search/${encodeURI(kw)}_${page}.html`); + const total = await this.querySelector(res, "#pagelink > span"); + if (total) { + if (parseInt(this.text(total).split("/")[1].slice(0, -1)) < page) { + return []; + } + const list = await this.querySelectorAll(res, ".book-li > a"); + const tasks = list.map(async (e) => { + const img = await this.querySelector(e.content, "img"); + const cover = await img.getAttributeText("data-src"); + const title = await img.getAttributeText("alt"); + let author = await this.querySelector(e.content, ".book-author"); + author = author.content.match(/svg>(.*)<\/span>/)[1].trim(); + if (author.indexOf("hot") > 0) { + author = author.match(/class="hot">(.*)<\/span>/)[1].trim() + author.split("")[1]; + } + const url = `${e.content.match(/href="(.*?)"/)[1]}|${title}|${cover}`; + return { title, url, cover, update: author }; + }); + return await Promise.all(tasks); + } + // 此时已经在详情页 + const head = await this.querySelector(res, "head"); + const desc = await this.querySelector(res, "#bookSummary > content"); + const title = await this.getAttributeText(head.content, "meta[property='og:title']", "content"); + const cover = await this.getAttributeText(head.content, "meta[property='og:image']", "content"); + const url = await this.getAttributeText(head.content, "meta[property='og:novel:read_url']", "content"); + return [ + { + title, + cover, + url: `${url.substring(25)}|${title}|${cover}|${this.text(desc).replace("
", "")}`, + update: await this.getAttributeText(head.content, "meta[property='og:novel:author']", "content"), + }, + ]; + } + + async detail(string) { + let promise; + const data = string.split("|"); + if (data.length == 3) { + promise = (async (data) => { + const res = await this.request(data[0]); + const desc = await this.querySelector(res, "#bookSummary > content"); + data.push(this.text(desc).replace("
", "")); + }).call(this, data); + data[0] = `${data[0].slice(0, -5)}/catalog`; + } + const catalog = await this.request(data[0]); + const volumes = await this.querySelectorAll(catalog, ".volume-chapters"); + const episodes = volumes.map(async (volume) => { + const title = this.text(await this.querySelector(volume.content, ".chapter-bar > h3")); + const urls = await this.querySelectorAll(volume.content, ".chapter-li-a"); + const tasks = await Promise.all( + urls.map(async (url) => ({ name: this.text(url), url: await url.getAttributeText("href") })) + ); + return { title, urls: tasks }; + }); + const newLocal = await Promise.all(episodes); + if (promise) await promise; + return { title: data[1], cover: data[2], desc: data[3], episodes: newLocal }; + } + + async watch(url) { + url = url.slice(0, -5); + const res = await this.request(`${url}_2.html`, { headers: { "Accept-Language": "zh-cn", Accept: "*/*" } }); + const subtitle = this.text(await this.querySelector(res, "#apage h1")); + const total = parseInt(subtitle.split("/")[1].slice(0, -1)) || 1; + let tasks = []; + for (let i = 1; i <= total; i++) { + if (i != 2) { + tasks.push(this.handle(`${url}_${i}.html`)); + } + } + tasks = await Promise.all(tasks); + if (total > 1) { + tasks.splice(1, 0, (await this.querySelectorAll(res, "#acontentz > p")).map(this.filter)); + } + return { title: "Test", subtitle: subtitle.split("(")[0], content: tasks.flat() }; + } +}