From 66f0e411880a9a633e0d61237f6d2e9401c689da Mon Sep 17 00:00:00 2001 From: Ethan Shen <42264778+nczitzk@users.noreply.github.com> Date: Fri, 14 Feb 2025 00:10:14 +0800 Subject: [PATCH] fix(cursor): Cursor Changelog (#18346) --- lib/routes/cursor/changelog.ts | 145 +++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 51 deletions(-) diff --git a/lib/routes/cursor/changelog.ts b/lib/routes/cursor/changelog.ts index 3a81f19315d665..fb6dc40f5f5d62 100644 --- a/lib/routes/cursor/changelog.ts +++ b/lib/routes/cursor/changelog.ts @@ -1,63 +1,106 @@ -import { Route } from '@/types'; +import { type Data, type DataItem, type Route, ViewType } from '@/types'; -import got from '@/utils/got'; -import { load } from 'cheerio'; +import ofetch from '@/utils/ofetch'; import { parseDate } from '@/utils/parse-date'; +import { type CheerioAPI, type Cheerio, type Element, load } from 'cheerio'; +import { type Context } from 'hono'; + +export const handler = async (ctx: Context): Promise => { + const limit: number = Number.parseInt(ctx.req.query('limit') ?? '100', 10); + + const baseUrl: string = 'https://www.cursor.com'; + const targetUrl: string = new URL('changelog', baseUrl).href; + + const response = await ofetch(targetUrl, { + headers: { + cookie: 'NEXT_LOCALE=en', + }, + }); + const $: CheerioAPI = load(response); + const language = $('html').attr('lang') ?? 'en'; + + const items: DataItem[] = $('article.relative') + .slice(0, limit) + .toArray() + .map((el): Element => { + const $el: Cheerio = $(el); + + const version: string = $el.find('div.items-center p').first().text(); + + const title: string = `[${version}] ${$el + .find(String.raw`h2 a.hover\:underline`) + .contents() + .first() + .text()}`; + const pubDateStr: string | undefined = $el.find('div.inline-flex p').first().text().trim(); + const linkUrl: string | undefined = $el.find(String.raw`h2 a.hover\:underline`).attr('href'); + const guid: string = `cursor-changelog-${version}`; + const upDatedStr: string | undefined = pubDateStr; + + const $h2El = $el.find('h2').first(); + + if ($h2El.length) { + $h2El.prevAll().remove(); + $h2El.remove(); + } + + const description: string = $el.html() || ''; + + const processedItem: DataItem = { + title, + description, + pubDate: pubDateStr ? parseDate(pubDateStr) : undefined, + link: linkUrl ? new URL(linkUrl, baseUrl).href : undefined, + guid, + id: guid, + content: { + html: description, + text: description, + }, + updated: upDatedStr ? parseDate(upDatedStr) : undefined, + language, + }; + + return processedItem; + }) + .filter((_): _ is DataItem => true); + + return { + title: $('title').text(), + description: $('meta[property="og:description"]').attr('content'), + link: targetUrl, + item: items, + allowEmpty: true, + image: $('meta[property="og:image"]').attr('content'), + language, + }; +}; + export const route: Route = { path: '/changelog', - categories: ['program-update'], - example: '/cursor/changelog', - url: 'www.cursor.com/changelog', name: 'Changelog', - maintainers: ['p3psi-boo'], + url: 'www.cursor.com', + maintainers: ['p3psi-boo', 'nczitzk'], + handler, + example: '/cursor/changelog', + parameters: undefined, + description: undefined, + categories: ['program-update'], + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportRadar: true, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, radar: [ { source: ['www.cursor.com/changelog'], - target: '/cursor/changelog', + target: '/changelog', }, ], - handler, + view: ViewType.Articles, }; - -async function handler() { - const url = 'https://www.cursor.com/changelog'; - - const response = await got({ - method: 'get', - url, - }); - - const $ = load(response.data); - - const alist = $('article'); - - const list = alist.toArray().map((item) => { - const leftSide = item.firstChild! as unknown as Element; - const version = $(leftSide.firstChild!).text(); - const dateLabel = $(leftSide.lastChild!).text(); - const date = parseDate(dateLabel); - - // 从第二个子元素开始到结束都是内容 - const content = item.children - .slice(1) - .map((child) => $(child).html()) - .join(''); - const titleElement = $('h2 a', item); - const link = titleElement.attr('href'); - const title = titleElement.text(); - - return { - title: `${version} - ${title}`, - description: content, - link: `https://www.cursor.com${link}`, - pubDate: date, - }; - }); - - return { - title: 'Cursor Changelog', - link: 'https://www.cursor.com/changelog', - item: list, - }; -}