UNPKG

rsshub

Version:
157 lines (155 loc) 6.52 kB
import "./esm-shims-CzJ_djXG.mjs"; import { t as config } from "./config-C37vj7VH.mjs"; import "./dist-BInvbO1W.mjs"; import "./logger-Czu8UMNd.mjs"; import "./ofetch-BIyrKU3Y.mjs"; import { n as parseRelativeDate, 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 { t as timezone } from "./timezone-D8cuwzTY.mjs"; import { t as rss_parser_default } from "./rss-parser-Dtop7M8f.mjs"; import { load } from "cheerio"; import queryString from "query-string"; //#region lib/routes/keylol/index.ts const threadIdRegex = /(\d+)-\d+-\d+/; const header = { Cookie: config.keylol.cookie ?? void 0 }; const route = { path: "/:path", name: "论坛", parameters: { path: "路径,默认为热点聚焦" }, categories: ["game"], example: "/keylol/f161-1", features: { requireConfig: [{ name: "KEYLOL_COOKIE", optional: true, description: `配置后可抓取具有阅读权限的帖子內容` }], requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["keylol.com/:path"], target: (params, url) => url.replaceAll("forum.php?", "") }], maintainers: ["nczitzk", "kennyfong19931"], handler, description: `::: tip 若订阅 [热点聚焦](https://keylol.com/f161-1),网址为 \`https://keylol.com/f161-1\`。截取 \`https://keylol.com/\` 到末尾的部分 \`f161-1\` 作为参数,此时路由为 [\`/keylol/f161-1\`](https://rsshub.app/keylol/f161-1)。 若订阅子分类 [试玩免费 - 热点聚焦](https://keylol.com/forum.php?mod=forumdisplay&fid=161&filter=typeid&typeid=459),网址为 \`https://keylol.com/forum.php?mod=forumdisplay&fid=161&filter=typeid&typeid=459\`。提取\`fid\`及\`typeid\` 作为参数,此时路由为 [\`/keylol/fid=161&typeid=459\`](https://rsshub.app/keylol/fid=161&typeid=459)。注意不要包括\`filter\`,会调用[全局的内容过滤](https://docs.rsshub.app/guide/parameters#filtering)。 :::` }; async function handler(ctx) { let queryParams = {}; const path = ctx.req.param("path"); if (/^f\d+-\d+/.test(path)) queryParams.fid = path.match(/^f(\d+)-\d+/)[1]; else queryParams = queryString.parse(path); queryParams.mod = "forumdisplay"; queryParams.orderby = "dateline"; queryParams.filter = "author"; let authorNameMap; try { authorNameMap = (await rss_parser_default.parseURL(`https://keylol.com/forum.php?mod=rss&fid=${queryParams.fid}&auth=0`)).items.map((item) => ({ threadId: item.link.match(threadIdRegex)[1], author: item.author })); } catch { authorNameMap = []; } const limit = ctx.req.query("limit") ? Number.parseInt(ctx.req.query("limit"), 10) : 30; const rootUrl = "https://keylol.com"; const currentUrl = queryString.stringifyUrl({ url: `${rootUrl}/forum.php`, query: queryParams }); const { data: response } = await got_default({ method: "get", url: currentUrl, headers: header }); const $ = load(response); let items = $("tbody[id^=\"normalthread_\"]").slice(0, limit).toArray().map((item) => { item = $(item); return { title: item.find("a.xst").text(), link: new URL(item.find(" a.xst").prop("href").split("&extra=")[0], rootUrl).href, author: item.find("td.by-author cite").text(), pubDate: parseRelativeDate(item.find("td.by-author em").text().replaceAll(" 发表", "")) }; }); items = await Promise.all(items.map((item) => cache_default.tryGet(item.link, async () => { const threadId = threadIdRegex.test(item.link) ? item.link.match(threadIdRegex)[1] : queryString.parseUrl(item.link).query.tid; const { data: detailResponse } = await got_default({ method: "get", url: item.link, headers: header }); const content = load(detailResponse); let descriptionList = []; const indexDiv = content("div#threadindex"); if (indexDiv.length > 0) { const postId = content("div.t_fsz > script").text().match(/show_threadindex\((\d+),/)[1]; descriptionList = await Promise.all(indexDiv.find("a").map((i, a) => { const pageTitle = $(a).text(); const page = $(a).attr("page"); return getPage(`${rootUrl}/forum.php?${queryString.stringify({ mod: "viewthread", tid: threadId, viewpid: postId, cp: page })}`, pageTitle); })); } else descriptionList.push(getDescription(content)); item.description = descriptionList.join("<br/>"); const realAuthorName = authorNameMap.find((a) => a.threadId === threadId); if (realAuthorName) item.author = realAuthorName.author; item.category = content("#keyloL_thread_tags a").toArray().map((c) => content(c).text()); const pubDateEm = content("img.authicn").first().next(); const pubDateMatches = (pubDateEm.find("span").prop("title") ?? pubDateEm.text()).match(/(\d{4}(?:-\d{1,2}){2} (?:\d{2}:){2}\d{2})/) ?? void 0; if (pubDateMatches) item.pubDate = timezone(parseDate(pubDateMatches[1], "YYYY-M-D HH:mm:ss"), 8); const updatedMatches = content("i.pstatus").text().match(/(\d{4}(?:-\d{1,2}){2} (?:\d{2}:){2}\d{2})/) ?? void 0; if (updatedMatches) item.updated = timezone(parseDate(updatedMatches[1], "YYYY-M-D HH:mm:ss"), 8); item.comments = content("div.subforum_right_title_left_down").text() ? Number.parseInt(content("div.subforum_right_title_left_down").text(), 10) : 0; return item; }))); const icon = $("link[rel=\"apple-touch-icon\"]").prop("href"); return { item: items, title: $("title").text(), link: currentUrl, description: $("meta[name=\"description\"]").prop("content"), language: "zh-cn", icon, logo: icon, subtitle: $("meta[name=\"application-name\"]").prop("content"), author: $("meta[name=\"author\"]").prop("content") }; } function getDescription($) { const descriptionEl = $("td.t_f"); descriptionEl.find("div.rnd_ai_pr").remove(); descriptionEl.find("img").each((_, img) => { img = $(img); if (img.attr("src")?.endsWith("none.gif") && img.attr("file")) { img.attr("src", img.attr("file")); img.removeAttr("file"); img.removeAttr("zoomfile"); } }); return descriptionEl.length > 0 ? descriptionEl.html() : $("div.alert_info").html(); } async function getPage(url, pageTitle) { const { data: detailResponse } = await got_default({ method: "get", url, headers: header }); const content = load(detailResponse, { xmlMode: true })("root").text(); return "<h3>" + pageTitle + "</h3>" + getDescription(load(content)); } //#endregion export { route };