rsshub
Version:
Make RSS Great Again!
109 lines (108 loc) • 4.43 kB
JavaScript
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 };