rsshub
Version:
Make RSS Great Again!
114 lines (113 loc) • 5.23 kB
JavaScript
import { t as parseDate } from "./parse-date-3kcy2Eau.mjs";
import { t as cache_default } from "./cache-C1Y-9qDV.mjs";
import { t as got_default } from "./got-DUpa1V3-.mjs";
import dayjs from "dayjs";
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
import { z } from "zod";
import { renderToString } from "hono/jsx/dom/server";
import utc from "dayjs/plugin/utc.js";
//#region lib/routes/readhub/templates/description.tsx
dayjs.extend(utc);
const renderDescription = ({ description, news, timeline, rootUrl }) => renderToString(/* @__PURE__ */ jsxs(Fragment, { children: [
description ? /* @__PURE__ */ jsx("p", { children: description }) : null,
news?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("h3", { children: "媒体报道" }), /* @__PURE__ */ jsx("table", {
cellspacing: "8",
children: /* @__PURE__ */ jsx("tbody", { children: news.map((item, index) => /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("a", {
href: item.url,
children: item.title
}) }), /* @__PURE__ */ jsx("th", {
align: "left",
children: /* @__PURE__ */ jsx("small", { children: item.siteNameDisplay })
})] }, String(item.url ?? item.title ?? index))) })
})] }) : null,
timeline?.topics?.length ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("h3", { children: "事件追踪" }), /* @__PURE__ */ jsx("table", {
cellspacing: "10",
children: /* @__PURE__ */ jsx("tbody", { children: timeline.topics?.map((topic, index) => /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
align: "left",
children: /* @__PURE__ */ jsx("small", { children: topic.publishDate ? dayjs(topic.publishDate).utcOffset(8).format("YYYY-MM-DD HH:mm:ss") : "" })
}), /* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsx("a", {
href: topic.uid ? new URL(`topic/${topic.uid}`, rootUrl).href : void 0,
children: topic.title
}) })] }, String(topic.uid ?? topic.title ?? index))) })
})] }) : null
] }));
//#endregion
//#region lib/routes/readhub/util.ts
const domain = "readhub.cn";
const rootUrl = `https://${domain}`;
const apiRootUrl = `https://api.${domain}`;
const apiTopicUrl = new URL("topic/list", apiRootUrl).href;
const apiDetailUrl = new URL("topic/detail", apiRootUrl).href;
const apiTimelineUrl = new URL("topic/timeline/list", apiRootUrl).href;
const namedEntry = z.object({ name: z.string() });
const newsSchema = z.object({
url: z.url(),
title: z.string(),
siteNameDisplay: z.string().nullish()
});
const topicSchema = z.object({
uid: z.string().min(1),
title: z.string().min(1),
summary: z.string().min(1),
url: z.url().nullish(),
publishDate: z.iso.datetime({ offset: true }),
siteNameDisplay: z.string().nullish(),
newsAggList: z.array(newsSchema),
entityList: z.array(namedEntry).nullish(),
tagList: z.array(namedEntry).nullish()
});
const timelineEntrySchema = z.object({
uid: z.string().min(1),
title: z.string(),
publishDate: z.iso.datetime({ offset: true }).nullish()
});
const timelineDataSchema = z.object({ items: z.array(timelineEntrySchema) });
const topicDataSchema = z.object({ items: z.array(topicSchema) });
const timelineSchema = z.object({ data: timelineDataSchema });
const detailSchema = z.object({ data: topicDataSchema });
async function fetchTopic(uid) {
const { data: detailResponse } = await got_default(apiDetailUrl, { searchParams: { uid } });
const detail = detailSchema.safeParse(detailResponse);
if (!detail.success) throw new Error("Readhub topic detail response is invalid or missing publication dates");
const matches = detail.data.data.items.filter((topic) => topic.uid === uid);
if (matches.length !== 1) throw new Error("Readhub topic detail response does not contain the requested topic");
const topic = matches[0];
const { data: timelineResponse } = await got_default(apiTimelineUrl, { searchParams: {
topic_uid: uid,
size: 10
} });
const timeline = timelineSchema.safeParse(timelineResponse);
if (!timeline.success) throw new Error("Readhub topic timeline response is invalid");
return {
title: topic.title,
link: topic.url ?? new URL(`topic/${topic.uid}`, rootUrl).href,
description: renderDescription({
description: topic.summary,
news: topic.newsAggList.map((news) => ({
...news,
siteNameDisplay: news.siteNameDisplay ?? void 0
})),
timeline: { topics: timeline.data.data.items.map((entry) => ({
...entry,
publishDate: entry.publishDate ?? void 0
})) },
rootUrl
}),
author: topic.siteNameDisplay ?? void 0,
category: [...topic.entityList ?? [], ...topic.tagList ?? []].map((entry) => entry.name),
guid: `readhub-${topic.uid}`,
pubDate: parseDate(topic.publishDate)
};
}
const processItems = (items) => Promise.all(items.map((item) => {
const url = new URL(item.link);
const topicPath = /^\/topic\/([^/]+)\/?$/.exec(url.pathname);
if (url.origin !== rootUrl || !topicPath) return {
...item,
guid: `readhub-${item.guid}`
};
const uid = decodeURIComponent(topicPath[1]);
return cache_default.tryGet(`readhub:topic:v2:${uid}`, () => fetchTopic(uid));
}));
//#endregion
export { renderDescription as a, rootUrl as i, apiTopicUrl as n, processItems as r, apiRootUrl as t };