feat(route/railway): add Railway blog configuration (#19678)

* feat(route/railway): add Railway blog configuration

* style: auto format

* feat(route/railway): update namespace for Railway Blog

* fix(route/railway): correct namespace name and URL for Railway

* Update lib/routes/railway/index.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
纪华裕 2025-07-25 20:29:30 +08:00 committed by GitHub
parent 5e92c1630c
commit 4a1e5c36aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 81 additions and 0 deletions

View File

@ -0,0 +1,73 @@
import { Route, DataItem } from '@/types';
import cache from '@/utils/cache';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import ofetch from '@/utils/ofetch';
import { Context } from 'hono';
export const route: Route = {
path: '/blog',
categories: ['blog'],
example: '/railway/blog',
url: 'blog.railway.com',
name: 'Blog',
maintainers: ['jihuayu'],
handler,
};
async function handler(ctx: Context) {
const limit = Number.parseInt(ctx.req.query('limit') || '10');
const items = await fetchArticles(limit);
return {
title: 'Railway articles',
link: 'https://blog.railway.com',
item: items,
};
}
export const fetchArticles = async (limit: number): Promise<DataItem[]> => {
const page = await ofetch('https://blog.railway.com/rss.xml', {
responseType: 'text',
});
const $ = load(page, { xml: true });
return Promise.all(
$('item')
.toArray()
.slice(0, limit)
.map<Promise<DataItem>>((element) => {
const id = $(element).find('guid').text();
return cache.tryGet(`railway:blogs:${id}`, async () => {
const title = $(element).find('title').text();
const pubDate = $(element).find('pubDate').text();
const link = $(element).find('link').text();
const { content } = await fetchArticleDetails(link);
return {
guid: id,
title,
link,
pubDate: parseDate(pubDate),
description: content,
} as DataItem;
}) as Promise<DataItem>;
})
);
};
export const fetchArticleDetails = async (url: string) => {
const page = await ofetch(url);
const $ = load(page);
const $article = $('article > section ');
return {
content: $article.html() ?? undefined,
};
};

View File

@ -0,0 +1,8 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: 'Railway',
url: 'railway.com',
description: '',
lang: 'en',
};