UNPKG

rsshub

Version:
109 lines (108 loc) 4.43 kB
import { n as parseRelativeDate } from "./parse-date-Cr0wQjV_.mjs"; import { t as timezone } from "./timezone-BBvDwS_3.mjs"; import { n as getTiebaPageContent } from "./common-DqeLZ7uH.mjs"; import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime"; import { load } from "cheerio"; import { renderToString } from "hono/jsx/dom/server"; import { raw } from "hono/html"; //#region lib/routes/baidu/tieba/utils.ts /** * 解析相对时间(如"回复于4小时前")为实际日期 */ function parseRelativeTime(timeStr) { return parseRelativeDate((timeStr || "").replace(/^回复于/, "").trim(), [ "M-D", "YYYY-MM-DD", "HH:mm", "YYYY-MM-DD HH:mm", "YYYY-M-D HH:mm" ]); } //#endregion //#region lib/routes/baidu/tieba/post.tsx /** * 获取最新的帖子回复(倒序查看) * * @param {*} id 帖子ID * @param {number} [lz=0] 是否只看楼主(0: 查看全部, 1: 只看楼主) * @param {number} [pn=7e6] 帖子最大页码(默认假设为 7e6,如果超出假设则根据返回的最大页码再请求一次,否则可以节省一次请求) * 这个默认值我测试下来 7e6 是比较接近最大值了,因为当我输入 8e6 就会返回第一页的数据而不是最后一页了 * @returns */ async function getPost(id, lz = 0, pn = 7e6) { const html = await getTiebaPageContent(`https://tieba.baidu.com/p/${id}?see_lz=${lz}&pn=${pn}`, `tieba:post:${id}:${lz}:${pn}`, { waitForSelector: ".virtual-list-item", timeout: 3e3 }); const $ = load(html); const max = Number.parseInt($("[max-page]").attr("max-page") || "0"); if (max > pn) return getPost(id, lz, max); return html; } const route = { path: ["/tieba/post/:id", "/tieba/post/lz/:id"], categories: ["bbs"], example: "/baidu/tieba/post/686961453", parameters: { id: "帖子 ID" }, features: { requireConfig: [{ name: "BAIDU_COOKIE", optional: false, description: "百度 cookie 值,用于需要登录的贴吧页面" }], requirePuppeteer: true, antiCrawler: true, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["tieba.baidu.com/p/:id"] }], name: "帖子动态", maintainers: ["u3u", "FlanChanXwO"], handler }; async function handler(ctx) { const id = ctx.req.param("id"); const lz = ctx.req.path.includes("lz") ? 1 : 0; const $ = load(await getPost(id, lz)); const title = $(".pb-title-wrap .pb-title").text().trim(); const list = $(".virtual-list-item"); if (list.length === 0) throw new Error("No post replies found. The post may not exist or the cookie is invalid."); return { title: lz ? `【只看楼主】${title}` : title, link: `https://tieba.baidu.com/p/${id}?see_lz=${lz}`, description: `${title}的最新回复`, item: list.toArray().map((element) => { const item = $(element); const authorName = item.find(".head-name").text().trim(); if (!authorName) return null; const contentItems = item.find(".pb-rich-text .pb-content-item"); let postContent = ""; contentItems.each((_, el) => { const html = $(el).html()?.trim(); if (html) postContent += `<p>${html}</p>`; }); const images = item.find(".image-list-wrapper img").toArray().map((img) => $(img).attr("src") || $(img).attr("data-src") || "").filter(Boolean).map((src) => `<img src="${src}" alt="${title}">`).join(""); const descText = item.find(".pc-pb-comments-desc, .comment-desc-left").text().trim(); const floorMatch = descText.match(/第(\d+)楼/); const floor = floorMatch ? `${floorMatch[1]}楼` : ""; const parsedDate = descText ? parseRelativeTime(descText) : null; const validPubDate = parsedDate && !Number.isNaN(parsedDate.getTime()) ? timezone(parsedDate, 8) : void 0; const postId = item.attr("data-post-id") || item.attr("id") || ""; const replyLink = postId ? `https://tieba.baidu.com/p/${id}?pid=${postId}#${postId}` : `https://tieba.baidu.com/p/${id}`; return { title: `${authorName} 回复了帖子《${title}》`, description: renderToString(/* @__PURE__ */ jsxs(Fragment, { children: [ postContent ? /* @__PURE__ */ jsx("div", { children: raw(postContent) }) : null, images ? /* @__PURE__ */ jsx("div", { children: raw(images) }) : null, floor ? /* @__PURE__ */ jsxs("p", { children: ["楼层:", floor] }) : null ] })), pubDate: validPubDate, author: authorName, link: replyLink }; }).filter((item) => item !== null) }; } //#endregion export { route };