RSSHub/lib/routes/humanlayer/blog.ts

98 lines
3.1 KiB
TypeScript

import { load } from 'cheerio';
import type { DataItem, Route } from '@/types';
import cache from '@/utils/cache';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
export const route: Route = {
path: '/blog',
categories: ['blog'],
example: '/humanlayer/blog',
parameters: {},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.humanlayer.dev/blog'],
target: '/humanlayer/blog',
},
],
name: 'Blog',
maintainers: ['zj1123581321'],
handler,
url: 'www.humanlayer.dev/blog',
};
async function handler() {
const baseUrl = 'https://www.humanlayer.dev';
const listUrl = `${baseUrl}/blog`;
const response = await ofetch(listUrl);
const $ = load(response);
const list = $('a.block.py-2.group[href^="/blog/"]')
.toArray()
.map((el) => {
const $el = $(el);
const href = $el.attr('href')!;
const title = $el.find('h2').text().trim();
const metaLine = $el.find('p.text-sm').text().trim();
const description = $el.find('p[style]').text().trim();
// meta format: "Author · Date · Read time · #tag1 #tag2"
const parts = metaLine.split('·').map((s) => s.trim());
const author = parts[0] || '';
const dateStr = parts[1] || '';
const category = parts[3]?.match(/#[\w-]+/g)?.map((t) => t.slice(1));
return {
title,
link: `${baseUrl}${href}`,
author,
description,
pubDate: dateStr ? parseDate(dateStr) : undefined,
category,
} as DataItem;
});
const items = (await Promise.all(
list.map((item) =>
cache.tryGet(item.link!, async () => {
const resp = await ofetch(item.link!);
const $detail = load(resp);
const ogTitle = $detail('meta[property="og:title"]').attr('content');
const ogDesc = $detail('meta[property="og:description"]').attr('content');
const publishedTime = $detail('meta[property="article:published_time"]').attr('content');
const ogAuthor = $detail('meta[property="article:author"]').attr('content');
const ogImage = $detail('meta[property="og:image"]').attr('content');
const content = $detail('div.prose').html();
return {
...item,
title: ogTitle || item.title,
description: content || ogDesc || item.description,
pubDate: publishedTime ? parseDate(publishedTime) : item.pubDate,
author: ogAuthor || item.author,
banner: ogImage,
} as DataItem;
})
)
)) as DataItem[];
return {
title: 'HumanLayer Blog',
link: listUrl,
language: 'en',
item: items,
};
}