diff --git a/example.env.server b/example.env.server index 8c920c5..4fd731e 100644 --- a/example.env.server +++ b/example.env.server @@ -2,4 +2,5 @@ G_CLIENT_ID= G_CLIENT_SECRET= JWT_SECRET= INIT_TABLE=true -ENABLE_CACHE=true \ No newline at end of file +ENABLE_CACHE=true +PRODUCTHUNT_API_TOKEN= \ No newline at end of file diff --git a/server/sources/douban.ts b/server/sources/douban.ts index 241d9ee..7c54e86 100644 --- a/server/sources/douban.ts +++ b/server/sources/douban.ts @@ -35,7 +35,6 @@ export default defineSource(async () => { Accept: "application/json, text/plain, */*", }, }) - console.log(res) return res.items.map(movie => ({ id: movie.id, title: movie.title, diff --git a/server/sources/producthunt.ts b/server/sources/producthunt.ts index 8ebd14e..79ca023 100644 --- a/server/sources/producthunt.ts +++ b/server/sources/producthunt.ts @@ -1,28 +1,56 @@ -import * as cheerio from "cheerio" +import process from "node:process" import type { NewsItem } from "@shared/types" +const apiKey = process.env.PRODUCTHUNT_API_TOKEN +const token = `Bearer ${apiKey}` export default defineSource(async () => { - const baseURL = "https://www.producthunt.com" - const html: any = await myFetch(baseURL) - const $ = cheerio.load(html) - const $main = $("[data-test=homepage-section-0] [data-test^=post-item]") + if (!apiKey) { + throw new Error("PRODUCTHUNT_API_TOKEN is not set") + } + const query = ` + query { + posts(first: 30, order: VOTES) { + edges { + node { + id + name + tagline + votesCount + url + slug + } + } + } + } + ` + + const response: any = await myFetch("https://api.producthunt.com/v2/api/graphql", { + method: "POST", + headers: { + "Authorization": token, + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify({ query }), + }) + 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().replace(/^\d+\.\s*/, "") - const id = $(el).attr("data-test")?.replace("post-item-", "") - const vote = $(el).find("[data-test=vote-button]").text() - if (url && id && title) { + const posts = response?.data?.posts?.edges || [] + + for (const edge of posts) { + const post = edge.node + if (post.id && post.name) { news.push({ - url: `${baseURL}${url}`, - title, - id, + id: post.id, + title: post.name, + url: post.url || `https://www.producthunt.com/posts/${post.slug}`, extra: { - info: `△︎ ${vote}`, + info: ` △︎ ${post.votesCount || 0}`, + hover: post.tagline, }, }) } - }) + } + return news })