From 1357d04b905bb8f2afad20c14075b24d80f55735 Mon Sep 17 00:00:00 2001 From: Ou Date: Wed, 9 Oct 2024 02:53:38 +0800 Subject: [PATCH] feat: add two source --- public/icons/coolapk.png | Bin 0 -> 7809 bytes server/sources/cankaoxiaoxi.ts | 24 +++++++++++++++++++++ server/sources/coolapk/index.ts | 37 ++++++++++++++++++++++++++++++++ server/sources/coolapk/utils.ts | 34 +++++++++++++++++++++++++++++ server/sources/index.ts | 6 +++++- shared/data.ts | 4 ++-- shared/sources.ts | 25 ++++++++++++++------- 7 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 public/icons/coolapk.png create mode 100644 server/sources/cankaoxiaoxi.ts create mode 100644 server/sources/coolapk/index.ts create mode 100644 server/sources/coolapk/utils.ts diff --git a/public/icons/coolapk.png b/public/icons/coolapk.png new file mode 100644 index 0000000000000000000000000000000000000000..0da403bc93b52f8558a87c3b656c6e56d790fb89 GIT binary patch literal 7809 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 Q|F8V3qM#{XEo&M2KO0x5_W%F@ literal 0 HcmV?d00001 diff --git a/server/sources/cankaoxiaoxi.ts b/server/sources/cankaoxiaoxi.ts new file mode 100644 index 0000000..958e895 --- /dev/null +++ b/server/sources/cankaoxiaoxi.ts @@ -0,0 +1,24 @@ +interface Res { + list: { + data: { + id: string + title: string + // 北京时间 + url: string + publishTime: string + } + }[] +} + +export default defineSource(async () => { + const res = await Promise.all(["zhongguo", "guandian", "gj"].map(k => $fetch(`https://china.cankaoxiaoxi.com/json/channel/${k}/list.json`) as Promise)) + if (!res?.[0]?.list?.length) throw new Error("Cannot fetch data") + return res.map(k => k.list).flat().map(k => ({ + id: k.data.id, + title: k.data.title, + extra: { + date: tranformToUTC(k.data.publishTime), + }, + url: k.data.url, + })).sort((m, n) => m.extra.date < n.extra.date ? 1 : -1).slice(0, 20) +}) diff --git a/server/sources/coolapk/index.ts b/server/sources/coolapk/index.ts new file mode 100644 index 0000000..0be6532 --- /dev/null +++ b/server/sources/coolapk/index.ts @@ -0,0 +1,37 @@ +import { load } from "cheerio" +import { genHeaders } from "./utils" + +interface Res { + data: { + id: string + // 多行 + message: string + // 起的标题 + editor_title: string + shareUrl: string + entityType: string + pubDate: string + // dayjs(dateline, 'X') + dateline: number + targetRow: { + // 374.4万热度 + subTitle: string + } + }[] +} + +export default defineSource(async () => { + const url = "https://api.coolapk.com/v6/page/dataList?url=%2Ffeed%2FstatList%3FcacheExpires%3D300%26statType%3Dday%26sortField%3Ddetailnum%26title%3D%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&title=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&subTitle=&page=1" + const r: Res = await $fetch(url, { + headers: genHeaders(), + }) + if (!r.data || r.data.length === 0) throw new Error("Failed to fetch") + return r.data.filter(k => k.id).map(i => ({ + id: i.id, + title: i.editor_title || load(i.message).text().split("\n")[0], + url: i.shareUrl, + extra: { + date: new Date(i.dateline * 1000).getTime(), + }, + })).slice(0, 20) +}) diff --git a/server/sources/coolapk/utils.ts b/server/sources/coolapk/utils.ts new file mode 100644 index 0000000..62bbc2d --- /dev/null +++ b/server/sources/coolapk/utils.ts @@ -0,0 +1,34 @@ +// https://github.com/DIYgod/RSSHub/blob/master/lib/routes/coolapk/utils.ts +import { Buffer } from "node:buffer" +import md5 from "md5" + +function getRandomDEVICE_ID() { + const r = [10, 6, 6, 6, 14] + const id = r.map(i => Math.random().toString(36).substring(2, i)) + return id.join("-") +} + +function get_app_token() { + const DEVICE_ID = getRandomDEVICE_ID() + const now = Math.round(Date.now() / 1000) + const hex_now = `0x${now.toString(16)}` + const md5_now = md5(now.toString()) + const s = `token://com.coolapk.market/c67ef5943784d09750dcfbb31020f0ab?${md5_now}$${DEVICE_ID}&com.coolapk.market` + const md5_s = md5(Buffer.from(s).toString("base64")) + const token = md5_s + DEVICE_ID + hex_now + return token +} + +export function genHeaders() { + return { + "X-Requested-With": "XMLHttpRequest", + "X-App-Id": "com.coolapk.market", + "X-App-Token": get_app_token(), + "X-Sdk-Int": "29", + "X-Sdk-Locale": "zh-CN", + "X-App-Version": "11.0", + "X-Api-Version": "11", + "X-App-Code": "2101202", + "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 10; Redmi K30 5G MIUI/V12.0.3.0.QGICMXM) (#Build; Redmi; Redmi K30 5G; QKQ1.191222.002 test-keys; 10) +CoolMarket/11.0-2101202", + } +} diff --git a/server/sources/index.ts b/server/sources/index.ts index ad99904..597286d 100644 --- a/server/sources/index.ts +++ b/server/sources/index.ts @@ -4,16 +4,20 @@ import zaobao from "./zaobao" import v2ex from "./v2ex" import ithome from "./ithome" import zhihu from "./zhihu" +import cankaoxiaoxi from "./cankaoxiaoxi" +import coolapk from "./coolapk" export const sourcesFn = { weibo, zaobao, v2ex, ithome, + zhihu, + coolapk, + cankaoxiaoxi, "peopledaily": defineRSSSource("https://feedx.net/rss/people.xml", { hiddenDate: true, }), - "zhihu": zhihu, "sputniknewscn": defineRSSHubSource("/sputniknews/news/chinese"), "douyin": defineFallbackSource("douyin"), "aljazeeracn": defineRSSSource("https://feedx.net/rss/aljazeera.xml"), diff --git a/shared/data.ts b/shared/data.ts index 552ecd0..78dad1a 100644 --- a/shared/data.ts +++ b/shared/data.ts @@ -13,7 +13,7 @@ export const metadata: Metadata = { }, china: { name: "国内", - sources: ["peopledaily", "toutiao", "zhihu"], + sources: ["peopledaily", "toutiao", "zhihu", "cankaoxiaoxi"], }, world: { name: "国外", @@ -25,6 +25,6 @@ export const metadata: Metadata = { }, tech: { name: "科技", - sources: ["ithome"], + sources: ["ithome", "coolapk"], }, } diff --git a/shared/sources.ts b/shared/sources.ts index c3c35e1..2d2c085 100644 --- a/shared/sources.ts +++ b/shared/sources.ts @@ -1,11 +1,20 @@ import { typeSafeObjectFromEntries } from "./type.util" import type { OriginSource, Source, SourceID } from "./types" +const Time = { + half: 30 * 60 * 1000, + five: 5 * 60 * 1000, +} + export const originSources = { "v2ex": { name: "V2EX", home: "https://v2ex.com/", }, + "coolapk": { + name: "酷安", + home: "https://coolapk.com", + }, "wallstreetcn": { name: "华尔街见闻", home: "https://wallstreetcn.com/", @@ -13,14 +22,19 @@ export const originSources = { }, "sputniknewscn": { name: "俄罗斯卫星通讯社", - interval: 30 * 60 * 1000, + interval: Time.half, home: "https://sputniknews.cn", }, "aljazeeracn": { name: "半岛电视台", - interval: 30 * 60 * 1000, + interval: Time.half, home: "https://chinese.aljazeera.net", }, + "cankaoxiaoxi": { + name: "参考消息", + interval: Time.half, + home: "https://china.cankaoxiaoxi.com", + }, "36kr": { name: "36氪", home: "https://36kr.com", @@ -58,18 +72,13 @@ export const originSources = { }, "thepaper": { name: "澎湃新闻", - interval: 30 * 60 * 1000, + interval: Time.half, home: "https://www.thepaper.cn", }, "toutiao": { name: "今日头条", home: "https://www.toutiao.com", }, - "cankaoxiaoxi": { - name: "参考消息", - interval: 60 * 60 * 1000, - home: "http://www.cankaoxiaoxi.com", - }, "ithome": { name: "IT之家", home: "https://www.ithome.com",