rsshub
Version:
Make RSS Great Again!
111 lines (110 loc) • 4.58 kB
JavaScript
import { t as config } from "./config-CCmw1BNE.mjs";
import { t as cache_default } from "./cache-BkqOokyU.mjs";
import { t as got_default } from "./got-BTowW50G.mjs";
import { t as ConfigNotFoundError } from "./config-not-found-fQ5mxvDU.mjs";
import { t as getPlaywrightPage } from "./playwright-o20DiLNh.mjs";
import { createHash } from "node:crypto";
import { Cookie } from "tough-cookie";
//#region lib/routes/baidu/tieba/common.ts
/**
* 解析百度 cookie 字符串为 Playwright 可用的 cookie 对象数组
* 正确处理包含 '=' 的 cookie 值
*/
function parseBaiduCookies(cookieStr) {
return cookieStr.split(";").map((c) => Cookie.parse(c.trim())).filter((c) => Boolean(c?.key)).map((c) => ({
name: c.key,
value: c.value,
domain: ".tieba.baidu.com",
path: "/"
}));
}
/**
* 检查 HTML 内容是否包含百度安全验证页面
*/
function checkSecurityVerification(html) {
if (html.includes("安全验证") || html.includes("百度安全验证")) throw new Error("Baidu security verification required. The cookie may be expired or invalid. Please update your BAIDU_COOKIE.");
}
/**
* 使用 Playwright 获取贴吧页面内容
* 包含统一的 cookie 设置、安全验证检查和缓存逻辑
* 带有重试机制处理瞬态错误
*/
async function getTiebaPageContent(url, cacheKey, options = {}) {
const cookie = config.baidu.cookie;
if (!cookie) throw new ConfigNotFoundError("Baidu Tieba RSS is disabled due to the lack of <a href=\"https://docs.rsshub.app/deploy/config#baidu\">BAIDU_COOKIE</a>");
const cookies = parseBaiduCookies(cookie);
const { waitForSelector = ".thread-card-wrapper, .virtual-list-item, .thread-content-box, .thread-card", timeout = 3e3, retries = 3 } = options;
return await cache_default.tryGet(cacheKey, async () => {
let lastError;
for (let attempt = 0; attempt < retries; attempt++) {
const { page, destroy } = await getPlaywrightPage(url, {
onBeforeLoad: async (page) => {
if (cookies.length > 0) await page.context().addCookies(cookies);
},
gotoConfig: { waitUntil: "domcontentloaded" }
});
try {
await new Promise((resolve) => setTimeout(resolve, 2e3));
try {
await page.waitForSelector(waitForSelector, { timeout });
} catch {}
const html = await page.content();
checkSecurityVerification(html);
return html;
} catch (error) {
lastError = error;
if (attempt === retries - 1) throw lastError;
await new Promise((resolve) => setTimeout(resolve, 1e3 * (attempt + 1)));
} finally {
await destroy();
}
}
throw lastError || /* @__PURE__ */ new Error("Failed to fetch page content");
}, config.cache.routeExpire, false);
}
/**
* 规范化 URL 为绝对地址
*/
function normalizeUrl(href, base = "https://tieba.baidu.com") {
if (!href) return "";
if (href.startsWith("http")) return href;
return `${base}${href.startsWith("/") ? href : `/${href}`}`;
}
/**
* 通过 /c/f/frs/page API 获取贴吧帖子列表
* 使用贴吧客户端签名认证,无需 Puppeteer
*/
const TIEBA_CLIENT_SECRET = "tiebaclient!!!";
function computeSign(params) {
const raw = Object.keys(params).toSorted().map((key) => `${key}=${params[key]}`).join("") + TIEBA_CLIENT_SECRET;
return createHash("md5").update(raw).digest("hex");
}
async function getTiebaForumData(params) {
const cookie = config.baidu.cookie;
if (!cookie) throw new ConfigNotFoundError("Baidu Tieba RSS is disabled due to the lack of <a href=\"https://docs.rsshub.app/deploy/config#baidu\">BAIDU_COOKIE</a>");
const bduss = cookie.match(/BDUSS=([^;]+)/)?.[1] || "";
if (!bduss) throw new ConfigNotFoundError("BAIDU_COOKIE must contain BDUSS. Please check your cookie configuration.");
const apiParams = {
_client_id: "wappc_1234567890123_456",
_client_type: "2",
_client_version: "12.20.1.0",
_phone_imei: "000000000000000",
from: "tieba",
kw: params.kw,
rn: "30",
pn: "1",
BDUSS: bduss
};
if (params.isGood) apiParams.is_good = "1";
if (params.cid && params.cid !== "0") apiParams.cid = params.cid;
if (params.sortBy === "replied") apiParams.sort_type = "1";
apiParams.sign = computeSign(apiParams);
const url = "https://tieba.baidu.com/c/f/frs/page";
const cacheKey = `tieba:api:forum:${params.kw}:${params.cid || "0"}:${params.sortBy || "created"}`;
return await cache_default.tryGet(cacheKey, async () => {
const { data: response } = await got_default.post(url, { form: apiParams });
return response;
}, config.cache.routeExpire, false);
}
//#endregion
export { getTiebaPageContent as n, normalizeUrl as r, getTiebaForumData as t };