From b1fb9d7285a48e5a0f78e4d161d19d67d93de2e0 Mon Sep 17 00:00:00 2001 From: Ou Date: Sat, 5 Oct 2024 01:22:41 +0800 Subject: [PATCH] feat: server routes --- public/icons/wallstreetcn.png | Bin 0 -> 5238 bytes server/sources/36kr-quick.ts | 4 +-- server/sources/36kr.ts | 5 ++++ server/sources/index.ts | 8 ++++-- server/sources/wallstreetcn.ts | 3 +++ server/utils/index.ts | 44 +++++++++++++++++++++++++++++---- shared/consts.ts | 3 +++ shared/data.ts | 24 +++++++++++------- shared/types.ts | 15 +++++++++++ 9 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 public/icons/wallstreetcn.png create mode 100644 server/sources/36kr.ts create mode 100644 server/sources/wallstreetcn.ts diff --git a/public/icons/wallstreetcn.png b/public/icons/wallstreetcn.png new file mode 100644 index 0000000000000000000000000000000000000000..01f050900b9be20d96b5890874bf39d39d5e8a66 GIT binary patch literal 5238 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 w^=E}&n_3>Q1eH6qiC2PwfdBvi literal 0 HcmV?d00001 diff --git a/server/sources/36kr-quick.ts b/server/sources/36kr-quick.ts index 9e4d3a9..7ad63ca 100644 --- a/server/sources/36kr-quick.ts +++ b/server/sources/36kr-quick.ts @@ -1,3 +1,3 @@ -import { defineRSSSource } from "#/utils" +import { defineRSSHubSource } from "#/utils" -export default defineRSSSource("https://rsshub.rssforever.com/36kr/newsflashes") +export default defineRSSHubSource("/36kr/newsflashes") diff --git a/server/sources/36kr.ts b/server/sources/36kr.ts new file mode 100644 index 0000000..782ad10 --- /dev/null +++ b/server/sources/36kr.ts @@ -0,0 +1,5 @@ +import { defineRSSHubSource } from "#/utils" + +export default defineRSSHubSource("/36kr/hot-list", { + sorted: false, +}) diff --git a/server/sources/index.ts b/server/sources/index.ts index 555d7ca..37b493d 100644 --- a/server/sources/index.ts +++ b/server/sources/index.ts @@ -2,7 +2,9 @@ import type { SourceID, SourceInfo } from "@shared/types" import peopledaily from "./peopledaily" import weibo from "./weibo" import zaobao from "./zaobao" -import kr from "./36kr-quick" +import krQ from "./36kr-quick" +import wallstreetcn from "./wallstreetcn" +// import kr from "./36kr" export { fallback } from "./fallback" @@ -10,5 +12,7 @@ export const sources = { peopledaily, weibo, zaobao, - "36kr-quick": kr, + wallstreetcn, + "36kr-quick": krQ, + // "36kr": kr, } as Record Promise> diff --git a/server/sources/wallstreetcn.ts b/server/sources/wallstreetcn.ts new file mode 100644 index 0000000..da04998 --- /dev/null +++ b/server/sources/wallstreetcn.ts @@ -0,0 +1,3 @@ +import { defineRSSHubSource } from "#/utils" + +export default defineRSSHubSource("/wallstreetcn/live") diff --git a/server/utils/index.ts b/server/utils/index.ts index 5bbcda3..ac34503 100644 --- a/server/utils/index.ts +++ b/server/utils/index.ts @@ -1,4 +1,5 @@ -import type { NewsItem, SourceInfo } from "@shared/types" +import { RSSHubBase } from "@shared/consts" +import type { NewsItem, RSSHubInfo, SourceInfo } from "@shared/types" export function defineSource(source: () => Promise): () => Promise { return async () => ({ @@ -9,11 +10,11 @@ export function defineSource(source: () => Promise): () => Promise Promise { return async () => { - const source = await rss2json(url) - if (!source?.items.length) throw new Error("Cannot fetch data") + const data = await rss2json(url) + if (!data?.items.length) throw new Error("Cannot fetch data") return { - updatedTime: source.updatedTime ?? Date.now(), - items: source.items.slice(0, 20).map(item => ({ + updatedTime: data.updatedTime ?? Date.now(), + items: data.items.slice(0, 20).map(item => ({ title: item.title, url: item.link, id: item.link, @@ -24,3 +25,36 @@ export function defineRSSSource(url: string): () => Promise { } } } + +interface Option { + // default: true + sorted?: boolean + // default: 20 + limit?: number +} +export function defineRSSHubSource(route: string, option?: Option): () => Promise { + return async () => { + const url = new URL(route, RSSHubBase) + url.searchParams.set("format", "json") + const defaultOption: Option = { + sorted: true, + limit: 20, + } + Object.assign(defaultOption, option) + Object.entries(defaultOption).forEach(([key, value]) => { + url.searchParams.set(key, value.toString()) + }) + const data: RSSHubInfo = await $fetch(url) + return { + updatedTime: Date.now(), + items: data.items.slice(0, 20).map(item => ({ + title: item.title, + url: item.url, + id: item.id ?? item.url, + extra: { + date: item.date_published, + }, + })), + } + } +} diff --git a/shared/consts.ts b/shared/consts.ts index 88b3ac5..9e1c384 100644 --- a/shared/consts.ts +++ b/shared/consts.ts @@ -3,3 +3,6 @@ export const TTL = 15 * 60 * 1000 * 默认刷新间隔,否则复用缓存 */ export const Interval = 30 * 60 * 1000 + +export const RSSHubBase = "https://rsshub.rssforever.com" +// export const RSSHubBase = "https://rsshub.pseudoyu.com" diff --git a/shared/data.ts b/shared/data.ts index cb239c1..6bdd5ef 100644 --- a/shared/data.ts +++ b/shared/data.ts @@ -3,12 +3,18 @@ import type { Metadata } from "./types" export const sectionIds = ["focus", "social", "china", "world", "digital"] as const export const sources = { - "36kr": { - name: "36氪", - type: "人气榜", + "wallstreetcn": { + name: "华尔街见闻", interval: 10, - home: "https://36kr.com", + home: "https://wallstreetcn.com/", + type: "快讯", }, + // "36kr": { + // name: "36氪", + // type: "人气榜", + // interval: 10, + // home: "https://36kr.com", + // }, "36kr-quick": { name: "36氪", type: "快讯", @@ -83,19 +89,19 @@ export const metadata: Metadata = { sourceList: [], }, social: { - name: "社交媒体", - sourceList: ["douyin", "hupu", "tieba", "weibo"], + name: "实时", + sourceList: ["douyin", "weibo", "36kr-quick", "wallstreetcn", "zaobao"], }, china: { name: "国内", - sourceList: ["peopledaily", "36kr", "toutiao", "36kr-quick"], + sourceList: ["peopledaily", "toutiao"], }, world: { name: "国外", - sourceList: ["zaobao"], + sourceList: [], }, digital: { name: "数码", - sourceList: ["36kr"], + sourceList: [], }, } diff --git a/shared/types.ts b/shared/types.ts index cafb985..1c5973f 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -52,3 +52,18 @@ export interface CacheInfo { updated: number expires: number } + +export interface RSSHubInfo { + title: string + home_page_url: string + description: string + items: RSSHubItem[] +} + +export interface RSSHubItem { + id: string + url: string + title: string + content_html: string + date_published: string +}