rsshub
Version:
Make RSS Great Again!
155 lines (152 loc) • 5.69 kB
JavaScript
import "./esm-shims-CzJ_djXG.mjs";
import "./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 { load } from "cheerio";
//#region lib/routes/hupu/types.ts
/**
* 用于区分不同数据项类型的类型守卫
*/
function isHomePostItem(item) {
return "url" in item && "isNews" in item;
}
//#endregion
//#region lib/routes/hupu/index.ts
const categories = {
nba: {
title: "NBA",
data: "newsData"
},
cba: {
title: "CBA",
data: "newsData"
},
soccer: {
title: "足球",
data: "news"
},
"": {
title: "首页",
data: "res"
}
};
const route = {
path: ["/dept/:category?", "/:category?"],
name: "手机虎扑网",
url: "m.hupu.com",
maintainers: ["nczitzk", "hyoban"],
example: "/hupu/nba",
parameters: { category: {
description: "分类,可选值:nba、cba、soccer,默认为空(首页)",
default: "",
options: Object.entries(categories).map(([key, value]) => ({
label: value.title,
value: key
}))
} },
description: `::: tip
电竞分类参见 [游戏热帖](https://bbs.hupu.com/all-gg) 的对应路由 [\`/hupu/all/all-gg\`](https://rsshub.app/hupu/all/all-gg)。
:::`,
categories: ["bbs"],
radar: [{
source: ["m.hupu.com/:category", "m.hupu.com/"],
target: "/:category"
}],
handler: async (ctx) => {
const c = ctx.req.param("category") || "";
if (!(c in categories)) throw new Error("Invalid category. Valid options are: " + Object.keys(categories).filter(Boolean).join(", "));
const category = c;
const currentUrl = `https://m.hupu.com/${category}`;
const scriptMatch = (await got_default({
method: "get",
url: currentUrl
})).data.match(/<script id="__NEXT_DATA__" type="application\/json">(.*?)<\/script>/);
if (!scriptMatch || !scriptMatch[1]) throw new Error(`Failed to find __NEXT_DATA__ script tag in page: ${currentUrl}`);
const fullJsonString = scriptMatch[1];
let fullData;
try {
fullData = JSON.parse(fullJsonString);
} catch (error) {
throw new Error(`Failed to parse full JSON data: ${error instanceof Error ? error.message : String(error)}`);
}
const { pageProps } = fullData.props;
const dataKey = categories[category].data;
if (!(dataKey in pageProps)) throw new Error(`Expected '${dataKey}' property not found in pageProps for category: ${category || "home"}`);
let items = (() => {
const data = pageProps[dataKey];
return Array.isArray(data) ? data : [];
})().map((item) => isHomePostItem(item) ? {
title: item.title,
link: item.url.replace(/bbs\.hupu.com/, "m.hupu.com/bbs"),
guid: item.tid,
category: item.label ? [item.label] : void 0
} : {
title: item.title,
pubDate: timezone(parseDate(item.publishTime), 8),
link: item.link.replace(/bbs\.hupu.com/, "m.hupu.com/bbs"),
guid: item.tid
});
items = await Promise.all(items.filter((item) => item.link && !/subject/.test(item.link)).map((item) => cache_default.tryGet(item.link, async () => {
try {
const content = load((await got_default({
method: "get",
url: item.link
})).data);
const author = content(".bbs-user-info-name, .bbs-user-wrapper-content-name-span").text();
const pubDateString = content(".second-line-user-info span:not([class])").text();
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
const currentDate = /* @__PURE__ */ new Date();
const monthDayTimePattern = /^(\d{2})-(\d{2}) (\d{2}):(\d{2})$/;
const timeOnlyPattern = /^(\d{1,2}):(\d{2})$/;
let processedDateString = pubDateString;
if (monthDayTimePattern.test(pubDateString)) processedDateString = `${currentYear}-${pubDateString}`;
else if (timeOnlyPattern.test(pubDateString)) processedDateString = `${currentYear}-${String(currentDate.getMonth() + 1).padStart(2, "0")}-${String(currentDate.getDate()).padStart(2, "0")} ${pubDateString}`;
const pubDate = [
item.pubDate,
timezone(parseDate(processedDateString), 8),
timezone(parseRelativeDate(pubDateString), 8)
].find((d) => d instanceof Date && !Number.isNaN(d.getTime()));
const categories$1 = content(".basketballTobbs_tag > a, .tag-player-team").toArray().map((c$1) => content(c$1).text()).filter(Boolean);
content(".basketballTobbs_tag").remove();
content(".hupu-img").each(function() {
const imgSrc = content(this).attr("data-gif") || content(this).attr("data-origin") || content(this).attr("src");
content(this).parent().html(`<img src="${imgSrc}">`);
});
const descriptionParts = [];
const mainContent = content("#bbs-thread-content, .bbs-content-font").html();
if (mainContent) descriptionParts.push(mainContent);
const videoWrapper = content(".header-video-wrapper");
if (videoWrapper.length > 0) {
const videoElement = videoWrapper.find("video");
if (videoElement.length > 0) {
const videoHtml = videoElement.prop("outerHTML");
if (videoHtml) descriptionParts.push(videoHtml);
}
}
const description = descriptionParts.length > 0 ? descriptionParts.join("") : void 0;
return {
...item,
author,
category: categories$1.length > 0 ? categories$1 : item.category,
description,
pubDate
};
} catch {
return item;
}
})));
return {
title: `虎扑 - ${categories[category].title}`,
link: currentUrl,
item: items
};
}
};
//#endregion
export { route };