From 3b66d0f08145b555265942f4d0a574d8e4f8aa20 Mon Sep 17 00:00:00 2001 From: Ou Date: Mon, 21 Oct 2024 17:00:51 +0800 Subject: [PATCH] feat: new source --- public/icons/tieba.png | Bin 5686 -> 4863 bytes server/api/s/[id].ts | 2 +- server/sources/douyin.ts | 20 ++------------------ server/sources/gelonghui.ts | 4 ++-- server/sources/index.ts | 4 ++++ server/sources/thepaper.ts | 23 +++++++++++++++++++++++ server/sources/tieba.ts | 26 ++++++++++++++++++++++++++ server/sources/xueqiu.ts | 2 +- server/types.ts | 17 ----------------- server/utils/date.ts | 1 + server/utils/source.ts | 21 ++------------------- shared/metadata.ts | 2 +- shared/sources.ts | 8 ++++++-- 13 files changed, 69 insertions(+), 61 deletions(-) create mode 100644 server/sources/thepaper.ts create mode 100644 server/sources/tieba.ts diff --git a/public/icons/tieba.png b/public/icons/tieba.png index e689d86a805b770798ea497a2b621964bf9e172c..1ba240972f9fa65d514d29af5ba88c51784e02c8 100644 GIT binary patch literal 4863 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 diff --git a/server/api/s/[id].ts b/server/api/s/[id].ts index ce76a31..991895f 100644 --- a/server/api/s/[id].ts +++ b/server/api/s/[id].ts @@ -13,7 +13,7 @@ export default defineEventHandler(async (event): Promise => { const isValid = (id: SourceID) => !id || !sources[id] || !sourcesGetters[id] if (isValid(id)) { - const redirectID = sources?.[id].redirect + const redirectID = sources?.[id]?.redirect if (redirectID) id = redirectID if (isValid(id)) throw new Error("Invalid source id") } diff --git a/server/sources/douyin.ts b/server/sources/douyin.ts index c559d6a..fe5a661 100644 --- a/server/sources/douyin.ts +++ b/server/sources/douyin.ts @@ -9,28 +9,12 @@ interface Res { } } -async function getDyCookies() { - try { - const cookisUrl = "https://www.douyin.com/passport/general/login_guiding_strategy/?aid=6383" - const data = await $fetch.raw(cookisUrl) - const pattern = /passport_csrf_token=(.*); Path/s - const matchResult = data.headers.get("set-cookie")?.[0]?.match(pattern) - if (matchResult && matchResult.length > 1) { - const cookieData = matchResult[1] - return cookieData - } - } catch (error) { - logger.error(`获取抖音 Cookie 出错: ${error}`) - return null - } -} - export default defineSource(async () => { const url = "https://www.douyin.com/aweme/v1/web/hot/search/list/?device_platform=webapp&aid=6383&channel=channel_pc_web&detail_list=1" - const cookie = await getDyCookies() + const cookie = (await $fetch.raw("https://www.douyin.com/passport/general/login_guiding_strategy/?aid=6383")).headers.getSetCookie() const res: Res = await $fetch(url, { headers: { - Cookie: `passport_csrf_token=${cookie}`, + cookie: cookie.join("; "), }, }) return res.data.word_list diff --git a/server/sources/gelonghui.ts b/server/sources/gelonghui.ts index 47d0b05..f657df8 100644 --- a/server/sources/gelonghui.ts +++ b/server/sources/gelonghui.ts @@ -12,7 +12,7 @@ export default defineSource(async () => { // https://www.kzaobao.com/shiju/20241002/170659.html const url = a.attr("href") const title = a.find("h2").text() - const info = $(el).find(".about-stocks").text() + const info = $(el).find(".time > span:nth-child(1)").text() // 第三个 p const relatieveTime = $(el).find(".time > span:nth-child(3)").text() if (url && title && relatieveTime) { @@ -27,5 +27,5 @@ export default defineSource(async () => { }) } }) - return news.sort((m, n) => n.extra!.date > m.extra!.date ? 1 : -1) + return news }) diff --git a/server/sources/index.ts b/server/sources/index.ts index 75bcce2..26a525c 100644 --- a/server/sources/index.ts +++ b/server/sources/index.ts @@ -14,6 +14,8 @@ import cls from "./cls" import sputniknewscn from "./sputniknewscn" import xueqiu from "./xueqiu" import gelonghui from "./gelonghui" +import tieba from "./tieba" +import thepaper from "./thepaper" import type { SourceGetter } from "#/types" export const sourcesGetters = { @@ -24,6 +26,7 @@ export const sourcesGetters = { zhihu, coolapk, cankaoxiaoxi, + thepaper, sputniknewscn, ...wallstreetcn, ...xueqiu, @@ -31,5 +34,6 @@ export const sourcesGetters = { douyin, ...cls, toutiao, + tieba, ...kr36, } as Record & Partial> diff --git a/server/sources/thepaper.ts b/server/sources/thepaper.ts new file mode 100644 index 0000000..de0d486 --- /dev/null +++ b/server/sources/thepaper.ts @@ -0,0 +1,23 @@ +interface Res { + data: { + hotNews: { + contId: string + name: string + pubTimeLong: string + }[] + } +} + +export default defineSource(async () => { + const url = "https://cache.thepaper.cn/contentapi/wwwIndex/rightSidebar" + const res: Res = await $fetch(url) + return res.data.hotNews + .map((k) => { + return { + id: k.contId, + title: k.name, + url: `https://www.thepaper.cn/newsDetail_forward_${k.contId}`, + mobileUrl: `https://m.thepaper.cn/newsDetail_forward_${k.contId}`, + } + }) +}) diff --git a/server/sources/tieba.ts b/server/sources/tieba.ts new file mode 100644 index 0000000..53a4006 --- /dev/null +++ b/server/sources/tieba.ts @@ -0,0 +1,26 @@ +interface Res { + data: { + bang_topic: { + topic_list: { + topic_id: string + topic_name: string + create_time: number + topic_url: string + + }[] + } + } +} + +export default defineSource(async () => { + const url = "https://tieba.baidu.com/hottopic/browse/topicList" + const res: Res = await $fetch(url) + return res.data.bang_topic.topic_list + .map((k) => { + return { + id: k.topic_id, + title: k.topic_name, + url: k.topic_url, + } + }) +}) diff --git a/server/sources/xueqiu.ts b/server/sources/xueqiu.ts index 34fbcbe..16618a8 100644 --- a/server/sources/xueqiu.ts +++ b/server/sources/xueqiu.ts @@ -26,7 +26,7 @@ const hotstock = defineSource(async () => { url: `https://xueqiu.com/s/${k.code}`, title: k.name, extra: { - info: `${k.percent}%`, + info: `${k.percent}% ${k.exchange}`, }, })) }) diff --git a/server/types.ts b/server/types.ts index d233e11..d5b3e31 100644 --- a/server/types.ts +++ b/server/types.ts @@ -57,21 +57,4 @@ export interface SourceOption { hiddenDate?: boolean } -export interface FallbackResponse { - code: number - message: string - name: string - title: string - subtitle: string - total: number - updateTime: string - data: { - title: string - desc: string - time?: string - url: string - mobileUrl: string - }[] -} - export type SourceGetter = () => Promise diff --git a/server/utils/date.ts b/server/utils/date.ts index 4029960..be74e28 100644 --- a/server/utils/date.ts +++ b/server/utils/date.ts @@ -141,6 +141,7 @@ function toDurations(matches: string[]) { export const parseDate = (date: string | number, ...options: any) => dayjs(date, ...options).toDate() export function parseRelativeDate(date: string, timezone: string = "Asia/Shanghai") { + if (date === "刚刚") return new Date() // 预处理日期字符串 date const theDate = toDate(date) diff --git a/server/utils/source.ts b/server/utils/source.ts index aca44ea..e4ca770 100644 --- a/server/utils/source.ts +++ b/server/utils/source.ts @@ -1,29 +1,12 @@ -import type { AllSourceID, SourceID } from "@shared/types" +import type { AllSourceID } from "@shared/types" import defu from "defu" -import type { FallbackResponse, RSSHubOption, RSSHubInfo as RSSHubResponse, SourceGetter, SourceOption } from "#/types" +import type { RSSHubOption, RSSHubInfo as RSSHubResponse, SourceGetter, SourceOption } from "#/types" type X = SourceGetter | Partial> export function defineSource(source: T): T { return source } -export function defineFallbackSource(id: SourceID, option?: SourceOption): SourceGetter { - return async () => { - const url = `https://smzdk.top/api/${id}/new` - const res: FallbackResponse = await $fetch(url) - if (res.code !== 200 || !res.data) throw new Error(res.message) - return res.data.map(item => ({ - extra: { - date: !option?.hiddenDate && item.time, - }, - id: item.url, - title: item.title, - url: item.url, - mobileUrl: item.mobileUrl, - })) - } -} - export function defineRSSSource(url: string, option?: SourceOption): SourceGetter { return async () => { const data = await rss2json(url) diff --git a/shared/metadata.ts b/shared/metadata.ts index 8ff2d05..2045783 100644 --- a/shared/metadata.ts +++ b/shared/metadata.ts @@ -7,7 +7,7 @@ export const columnIds = ["focus", "realtime", "hottest", "china", "world", "tec const originMetadata: Metadata = { china: { name: "国内", - sources: ["weibo", "douyin", "toutiao", "zhihu"], + sources: ["zhihu", "thepaper"], }, world: { name: "国际", diff --git a/shared/sources.ts b/shared/sources.ts index 0d7d3ce..a608623 100644 --- a/shared/sources.ts +++ b/shared/sources.ts @@ -96,7 +96,9 @@ export const originSources = { }, "tieba": { name: "百度贴吧", - disable: true, + title: "热议", + type: "hottest", + color: "blue", home: "https://tieba.baidu.com", }, "toutiao": { @@ -114,7 +116,9 @@ export const originSources = { "thepaper": { name: "澎湃新闻", interval: Time.Common, - disable: true, + type: "hottest", + title: "热榜", + color: "gray", home: "https://www.thepaper.cn", }, "sputniknewscn": {