rsshub
Version:
Make RSS Great Again!
193 lines (192 loc) • 8 kB
JavaScript
import { t as parseDate } from "./parse-date-Cr0wQjV_.mjs";
import { t as cache_default } from "./cache-BkqOokyU.mjs";
import { t as got_default } from "./got-BTowW50G.mjs";
import dayjs from "dayjs";
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
import { load } from "cheerio";
import { renderToString } from "hono/jsx/dom/server";
//#region lib/routes/chnmuseum/namespace.ts
const namespace = {
name: "National Museum Of China",
url: "www.chnmuseum.cn",
description: "中国国家博物馆(National Museum of China)位于北京市中心天安门广场东侧,东长安街南侧,与人民大会堂东西相对称,是一座系统展示中华民族文化历史的综合性博物馆,也是世界上最大的博物馆之一。",
zh: { name: "中国国家博物馆" }
};
//#endregion
//#region lib/routes/chnmuseum/zl.tsx
const titleTagMap = {
zhanlanyugao: "正在展出",
jbcl: "基本陈列",
ztcl: "专题展览",
lszl: "临时展览",
"lszl/lswh": "临时展览 - 历史文化",
"lszl/gjjl": "临时展览 - 国际交流",
"lszl/zdzt": "临时展览 - 重大主题",
"lszl/yscx": "临时展览 - 艺术创新",
gjzl: "国家展览",
gbxz: "国博巡展"
};
const formatExhibitionDate = (dateStr) => {
if (!dateStr) return;
return dayjs(dateStr.replaceAll(/[年月/.]/g, "-").replaceAll("日", "")).format("YYYY-MM-DD");
};
const parseExhibitionDuration = (duration) => {
if (!duration) return {
startDate: void 0,
endDate: void 0
};
const cleanStr = duration.replaceAll(/\s+/g, "").replaceAll(/([^)]*)/g, "");
const allDates = cleanStr.match(/(\d{4}[./年-]\d{1,2}[./月-]\d{1,2}日?)|(\d{1,2}[./月-]\d{1,2}日?)/g) || [];
let startDateRaw;
let endDateRaw;
if (allDates.length >= 2) {
startDateRaw = allDates[0];
let rawEnd = allDates[1];
if (!/\d{4}/.test(rawEnd) && startDateRaw) {
const startYear = startDateRaw.match(/^\d{4}/);
if (startYear?.[0]) rawEnd = `${startYear[0]}${startDateRaw[4]}${rawEnd}`;
}
endDateRaw = rawEnd;
} else if (allDates.length === 1) if (cleanStr.includes("闭展")) endDateRaw = allDates[0];
else startDateRaw = allDates[0];
return {
startDate: formatExhibitionDate(startDateRaw),
endDate: formatExhibitionDate(endDateRaw)
};
};
const resolveRouteConfig = (type, subtype, baseUrl) => {
let url = `${baseUrl}/zl/`;
let cleanType = "";
if (type) {
cleanType = subtype ? `${type}/${subtype}` : type;
url = `${baseUrl}/zl/${cleanType}/`;
}
return {
cleanType,
url,
titleTag: titleTagMap[cleanType] || "展览"
};
};
const buildItemLink = (rawLink, contextUrl, baseUrl) => rawLink ? new URL(rawLink, contextUrl).href : baseUrl;
const buildExhibitionLink = (rawZtzl, itemLink, baseUrl) => rawZtzl ? new URL(rawZtzl, baseUrl).href : itemLink;
const fetchTargetElements = async (cleanType, subtype, url, baseUrl) => {
const items = [];
const seenLinks = /* @__PURE__ */ new Set();
const extractItems = (html, contextUrl) => {
const $ = load(html);
const pageElements = $(["ul[id=\"div\"] > li > a", "li.scale_imgs > a"].join(", ")).not(".zl_lszl_list *").toArray();
for (const el of pageElements) {
const $item = $(el).closest("li");
if ($item.length > 0) {
const rawLink = $(el).attr("href") || "";
const rawZtzl = $(el).attr("ztzlurl") || "";
const itemLink = buildItemLink(rawLink, contextUrl, baseUrl);
const exhibitionLink = buildExhibitionLink(rawZtzl, itemLink, baseUrl);
if (exhibitionLink && !seenLinks.has(exhibitionLink)) {
seenLinks.add(exhibitionLink);
items.push({
$item,
contextUrl,
itemLink,
exhibitionLink,
rawZtzl
});
}
}
}
};
if (cleanType === "lszl") {
const subKeys = Object.keys(titleTagMap).filter((key) => key.startsWith("lszl/"));
const pagesData = await Promise.all(subKeys.map(async (subKey) => {
const targetSubUrl = `${baseUrl}/zl/${subKey}/`;
return {
html: (await got_default(targetSubUrl)).data,
targetSubUrl
};
}));
for (const page of pagesData) extractItems(page.html, page.targetSubUrl);
} else extractItems((await got_default(url)).data, url);
return items;
};
const route = {
path: "/zl/:type?/:subType?",
categories: ["travel"],
example: "/chnmuseum/zl/lszl/zdzt",
parameters: {
type: "Exhibition type, supported values: zhanlanyugao(正在展出)、jbcl(基本陈列)、ztcl(专题展览)、lszl(临时展览)、gjzl(国家展览)、gbxz(国博巡展). Default: All exhibitions.",
subType: "subtype only works under type lszl(临时展览), supported values: zdzt(重大主题)、lswh(历史文化)、yscx(艺术创新)、gjjl(国际交流)"
},
name: "Exhibitions",
maintainers: ["magazian"],
radar: [{
source: ["www.chnmuseum.cn/zl/"],
target: "/zl"
}],
handler: async (ctx) => {
const type = ctx.req.param("type");
const subtype = ctx.req.param("subType");
const museumName = namespace.zh?.name || namespace.name;
const baseUrl = "https://www.chnmuseum.cn";
const { cleanType, url, titleTag } = resolveRouteConfig(type, subtype, baseUrl);
const itemsToParse = await fetchTargetElements(cleanType, subtype, url, baseUrl);
const list = (await Promise.all(itemsToParse.map(({ $item, contextUrl }) => {
const aTag = $item.find("a").first();
const rawLink = aTag.attr("href") || "";
const itemLink = buildItemLink(rawLink, contextUrl, baseUrl);
return cache_default.tryGet(itemLink, async () => {
const rawZtzl = aTag.attr("ztzlurl") || "";
const exhibitionLink = buildExhibitionLink(rawZtzl, itemLink, baseUrl);
const imgTag = $item.find("img");
let title = $item.find(".hide_title").text() || "";
const rawSrc = imgTag.attr("src");
const imgUrl = new URL(rawSrc, contextUrl).href;
const hideBox = $item.find(".hide_box");
const hideBoxes = hideBox.toArray().map((_, i) => hideBox.eq(i));
const findValue = (keyword) => hideBoxes.find((box) => box.find("p").first().text().includes(keyword))?.find("p").last().text() ?? "";
const location = findValue("地点");
let fullDuration = findValue("展期");
if (!title || title.endsWith("...")) {
const detailResponse = await got_default(itemLink);
const $detail = load(detailResponse.data);
title = $detail(".crumb_mod_box .title").text() || $detail("title").text().replace(/-?\s*中国国家博物馆/, "");
if (!fullDuration) {
const textDuration = $detail("li, strong, p").toArray().map((el) => $detail(el).text().trim()).find((text) => text.startsWith("展期:") || text.includes("闭展"))?.replace("展期:", "").trim();
const regexDuration = detailResponse.data.match(/var\s+qtxszq\s*=\s*"(.*?)";/)?.[1];
fullDuration = textDuration || regexDuration || "";
}
}
const { startDate, endDate } = parseExhibitionDuration(fullDuration);
const pubDate = startDate ? parseDate(startDate) : void 0;
const description = renderToString(/* @__PURE__ */ jsxs("div", { children: [
/* @__PURE__ */ jsx("img", { src: imgUrl }),
/* @__PURE__ */ jsx("br", {}),
/* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("b", { children: "地点:" }), location || "参考详情"] }),
/* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("b", { children: "开展:" }), startDate || "未定/常设"] }),
/* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("b", { children: "闭展:" }), endDate || "未定/常设"] }),
fullDuration && /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsxs("small", { children: ["原始展期:", fullDuration] }) })
] }));
return {
title,
link: exhibitionLink,
guid: itemLink,
pubDate,
description,
_extra: {
museumName,
location,
startDate,
endDate
}
};
});
}))).filter((i) => i !== null);
return {
title: `${museumName} - ${titleTag}`,
link: url,
language: "zh-CN",
item: list
};
}
};
//#endregion
export { route };