diff --git a/public/icons/github.png b/public/icons/github.png new file mode 100644 index 0000000..ea51207 Binary files /dev/null and b/public/icons/github.png differ diff --git a/public/icons/producthunt.png b/public/icons/producthunt.png new file mode 100644 index 0000000..fafe5b0 Binary files /dev/null and b/public/icons/producthunt.png differ diff --git a/server/glob.d.ts b/server/glob.d.ts index 1efdb4b..9a6776e 100644 --- a/server/glob.d.ts +++ b/server/glob.d.ts @@ -8,8 +8,10 @@ declare module 'glob:./sources/{*.ts,**/index.ts}' { export const douyin: typeof import('./sources/douyin') export const fastbull: typeof import('./sources/fastbull') export const gelonghui: typeof import('./sources/gelonghui') + export const github: typeof import('./sources/github') export const hackernews: typeof import('./sources/hackernews') export const ithome: typeof import('./sources/ithome') + export const producthunt: typeof import('./sources/producthunt') export const solidot: typeof import('./sources/solidot') export const sputniknewscn: typeof import('./sources/sputniknewscn') export const thepaper: typeof import('./sources/thepaper') diff --git a/server/sources/github.ts b/server/sources/github.ts new file mode 100644 index 0000000..466b303 --- /dev/null +++ b/server/sources/github.ts @@ -0,0 +1,34 @@ +import * as cheerio from "cheerio" +import type { NewsItem } from "@shared/types" + +const trending = defineSource(async () => { + const baseURL = "https://github.com" + const html: any = await $fetch("https://github.com/trending?spoken_language_code=") + const $ = cheerio.load(html) + const $main = $("main .Box div[data-hpc] > article") + const news: NewsItem[] = [] + $main.each((_, el) => { + const a = $(el).find(">h2 a") + const title = a.text().replace(/\n+/g, "").trim() + const url = a.attr("href") + const star = $(el).find("[href$=stargazers]").text().replace(/\s+/g, "").trim() + const desc = $(el).find(">p").text().replace(/\n+/g, "").trim() + if (url && title) { + news.push({ + url: `${baseURL}${url}`, + title, + id: url, + extra: { + info: `✰ ${star}`, + hover: desc, + }, + }) + } + }) + return news +}) + +export default defineSource({ + "github": trending, + "github-trending-today": trending, +}) diff --git a/server/sources/producthunt.ts b/server/sources/producthunt.ts new file mode 100644 index 0000000..3826e25 --- /dev/null +++ b/server/sources/producthunt.ts @@ -0,0 +1,28 @@ +import * as cheerio from "cheerio" +import type { NewsItem } from "@shared/types" + +export default defineSource(async () => { + const baseURL = "https://www.producthunt.com/" + const html: any = await $fetch(baseURL) + const $ = cheerio.load(html) + const $main = $("[data-test^=post-item]") + const news: NewsItem[] = [] + $main.each((_, el) => { + const a = $(el).find("a").first() + const url = a.attr("href") + const title = $(el).find("a[data-test^=post-name]").text() + const id = $(el).attr("data-test")?.replace("post-item-", "") + const vote = $(el).find("[data-test=vote-button]").text() + if (url && id && title) { + news.push({ + url: `${baseURL}${url}`, + title, + id, + extra: { + info: `△︎ ${vote}`, + }, + }) + } + }) + return news +}) diff --git a/shared/metadata.ts b/shared/metadata.ts index 25816a6..897e68f 100644 --- a/shared/metadata.ts +++ b/shared/metadata.ts @@ -15,7 +15,7 @@ const originMetadata: Metadata = { }, tech: { name: "科技", - sources: ["hackernews", "v2ex", "ithome", "coolapk", "solidot"], + sources: ["hackernews", "producthunt", "github-trending-today", "v2ex", "ithome", "coolapk", "solidot"], }, finance: { name: "财经", diff --git a/shared/sources.ts b/shared/sources.ts index 93de7de..953e497 100644 --- a/shared/sources.ts +++ b/shared/sources.ts @@ -197,6 +197,23 @@ export const originSources = { type: "hottest", home: "https://news.ycombinator.com/", }, + "producthunt": { + name: "Product Hunt", + color: "orange", + type: "hottest", + home: "https://www.producthunt.com/", + }, + "github": { + name: "Github", + color: "gray", + home: "https://github.com/", + sub: { + "trending-today": { + title: "Today", + type: "hottest", + }, + }, + }, } as const satisfies Record export const sources = genSources() diff --git a/shared/types.ts b/shared/types.ts index 55e0aa6..a8d8ae5 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -15,12 +15,12 @@ export type SourceID = { }[keyof SubSource] | Key : Key; }[MainSourceID] -// export type AllSourceID = { -// [Key in MainSourceID]: ConstSources[Key] extends { sub?: infer SubSource } ? keyof { -// // @ts-expect-error >_< -// [SubKey in keyof SubSource as `${Key}-${SubKey}`]: never -// } | Key : Key -// }[MainSourceID] +export type AllSourceID = { + [Key in MainSourceID]: ConstSources[Key] extends { sub?: infer SubSource } ? keyof { + // @ts-expect-error >_< + [SubKey in keyof SubSource as `${Key}-${SubKey}`]: never + } | Key : Key +}[MainSourceID] // export type DisabledSourceID = Exclude