UNPKG

rsshub

Version:
165 lines (162 loc) 6.28 kB
import "./esm-shims-CzJ_djXG.mjs"; import "./config-C37vj7VH.mjs"; import "./dist-BInvbO1W.mjs"; import "./logger-Czu8UMNd.mjs"; import "./ofetch-BIyrKU3Y.mjs"; import { t as parseDate } from "./parse-date-BrP7mxXf.mjs"; import { t as cache_default } from "./cache-Bo__VnGm.mjs"; import "./helpers-DxBp0Pty.mjs"; import { t as got_default } from "./got-KxxWdaxq.mjs"; import { load } from "cheerio"; import { CookieJar } from "tough-cookie"; //#region lib/routes/yuque/utils.ts const card2Html = (elem, link) => { const name = elem.attr("name"); const data = elem.attr("value")?.split("data:")[1]?.replace("undefined", ""); const value = JSON.parse(decodeURIComponent(data || "[]")); let html = ""; switch (name) { case "board": case "emoji": case "flowchart2": case "image": case "math": case "mindmap": case "puml": html = `<img src='${value.src}'>`; break; case "bookmarkInline": case "bookmarklink": case "yuqueinline": html = `<a href='${value.src}'>${value.detail.title}</a>`; break; case "checkbox": html = `<input type='checkbox' ${value === true ? "checked" : ""}>`; break; case "codeblock": html = `<code>${value.code.replaceAll("\n", "<br>")}</code>`; break; case "diagram": html = `<img src='${value.url}'>`; break; case "file": case "localdoc": html = `<a href='${value.src}'>${value.name}</a>`; break; case "hr": html = "<hr>"; break; case "label": html = `<b>${value.label}</b>`; break; case "mention": html = `<a href='https://www.yuque.com/${value.login}'>${value.name}</a>`; break; case "table": html = value.html; break; case "thirdparty": case "youku": if (elem.attr("alias") === "music163") html = `<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" height=66 src="${value.src}"></iframe>`; else if (elem.attr("alias") === "bilibili" || elem.attr("alias") === void 0) html = `<iframe src="${value.src}&high_quality=1&autoplay=0" width="650" height="477" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe>`; else if (value.type === "codepen") html = `<iframe height="265" style="width: 100%;" scrolling="no" title="codepen" src="${value.url}" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe>`; else throw new Error(`Unhandled thirdparty on ${link}: ${elem.attr("alias")}`); break; case "yuque": if (value.mode === "card") html = `<a href='${value.src}'>${value.detail.title}</a>`; else if (value.mode === "embed") html = `<iframe src="${value.url}" width="100%" height="518"></iframe>`; else throw new Error(`Unhandled mode on ${link}: ${value.mode}`); break; case "video": html = `<video src='${value.videoId}'></video>`; break; default: throw new Error(`Unhandled card on ${link}: ${name}`); } elem.replaceWith(html); }; //#endregion //#region lib/routes/yuque/book.ts const APP_DATA_REGEX = /window\.appData = JSON\.parse\(decodeURIComponent\("(.+?)"\)\);/; const baseUrl = "https://www.yuque.com"; const route = { path: "/:name/:book", categories: ["study"], example: "/yuque/ruanyf/weekly", parameters: { name: "用戶名", book: "知识库 ID" }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["yuque.com/:name/:book"] }], name: "知识库", maintainers: ["aha2mao", "ltaoo"], handler, description: `| Node.js 专栏 | 阮一峰每周分享 | 语雀使用手册 | | -------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------- | | [/yuque/egg/nodejs](https://rsshub.app/yuque/egg/nodejs) | [/yuque/ruanyf/weekly](https://rsshub.app/yuque/ruanyf/weekly) | [/yuque/yuque/help](https://rsshub.app/yuque/yuque/help) |` }; async function handler(ctx) { const cookieJar = new CookieJar(); const { name, book } = ctx.req.param(); const bookUrl = `${baseUrl}/${name}/${book}`; const { data: bookHtml } = await got_default(bookUrl, { cookieJar }); const $ = load(bookHtml); const appData = JSON.parse(decodeURIComponent($("script").text().match(APP_DATA_REGEX)[1])); const bookId = appData.book.id; const { data: { data: docs } } = await got_default(`${baseUrl}/api/docs`, { searchParams: { book_id: bookId }, cookieJar }); const list = docs.map((item) => ({ title: item.title, description: item.description, link: `${baseUrl}/${name}/${book}/${item.slug}`, pubDate: parseDate(item.published_at), slug: item.slug })); const items = await Promise.all(list.map((item) => cache_default.tryGet(item.link, async () => { const { data: { data } } = await got_default(`${baseUrl}/api/docs/${item.slug}`, { searchParams: { book_id: bookId, include_contributors: true } }); const $$1 = load(data.content, null, false); $$1("card").each((_, elem) => { card2Html($$1(elem), item.link); }); $$1("[data-lake-id]").removeAttr("data-lake-id"); $$1("[id]").removeAttr("id"); $$1("p").each((_, elem) => { elem = $$1(elem); if (elem.children().length === 1 && elem.children().is("br")) elem.remove(); if (elem.children().length === 2 && elem.children().eq(0).is("span") && elem.children().eq(0).text().length === 1 && elem.children().eq(1).is("br")) elem.remove(); }); for await (const v of $$1("video").toArray()) { const $v = $$1(v); const src = $v.attr("src"); if (src.startsWith("inputs")) { const { data: data$1 } = await got_default(`${baseUrl}/api/video`, { searchParams: { video_id: src } }); const { info } = data$1.data; $v.replaceWith(`<video controls preload='none' poster='${info.cover}'><source src='${info.url}' type='video/mp4'></video>`); } } item.description = $$1.html(); item.author = data.contributors.map((c) => c.name).join(", "); return item; }))); return { title: appData.book.name, description: appData.book.description, image: appData.group.avatar, link: bookUrl, item: items }; } //#endregion export { route };