UNPKG

rsshub

Version:
114 lines (113 loc) 5.23 kB
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 };