rsshub
Version:
Make RSS Great Again!
133 lines (111 loc) • 4.69 kB
text/typescript
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
import { load } from 'cheerio';
import timezone from '@/utils/timezone';
import { parseDate, parseRelativeDate } from '@/utils/parse-date';
/**
* Convert an array into a dictionary object.
* The keys of the dictionary object are the `id` properties of the elements in the array,
* and the values are the remaining properties of each element.
* @param {Array} arr - The array to be converted.
* @returns {Object} - The converted dictionary object.
*/
const arrayToDictionary = (arr) =>
Object.fromEntries(
arr.map(({ id, ...rest }) => [
id,
{
...rest,
},
])
);
export const route: Route = {
path: '/:proma?',
categories: ['new-media'],
example: '/latepost',
parameters: { proma: '栏目 id,见下表,默认为最新报道' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: '报道',
maintainers: ['nczitzk'],
handler,
description: `| 最新报道 | 晚点独家 | 人物访谈 | 晚点早知道 | 长报道 |
| -------- | -------- | -------- | ---------- | ------ |
| | 1 | 2 | 3 | 4 |`,
};
async function handler(ctx) {
const proma = ctx.req.param('proma');
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 5;
const title = '晚点';
const defaultTitle = '最新报道';
const exclusiveCategory = '晚点独家';
const rootUrl = 'https://www.latepost.com';
const currentUrl = new URL(proma ? `news/index?proma=${proma}` : '', rootUrl).href;
const apiColumnUrl = new URL('site/get-column', rootUrl).href;
const apiCommentUrl = new URL('news/get-comment', rootUrl).href;
const apiUrl = new URL(proma ? 'news/get-news-data' : 'site/index', rootUrl).href;
const { data: columnResponse } = await got(apiColumnUrl);
const columns = arrayToDictionary(columnResponse?.data ?? []);
const { data: response } = await got.post(apiUrl, {
form: {
page: 1,
limit,
programa: Number.parseInt(proma, 10),
},
});
let items = response.data.slice(0, limit).map((item) => ({
title: item.title,
link: new URL(item.detail_url, rootUrl).href,
category: [item.is_dj ? exclusiveCategory : undefined, item.programa ? columns[item.programa]?.title : undefined, ...item.label.map((c) => c.label)],
guid: item.id,
pubDate: parseDate(item.release_time, ['MM月DD日', 'YYYY年MM月DD日']),
}));
items = await Promise.all(
items.map((item) =>
cache.tryGet(item.link, async () => {
const { data: detailResponse } = await got(item.link);
const { data: commentResponse } = await got.post(apiCommentUrl, {
news_id: item.guid,
page: 1,
limit: Infinity,
sort: 1,
delete_num: 0,
});
const content = load(detailResponse);
item.title = item.title ?? content('div.article-header-title').text();
item.description = content('#select-main').html().replaceAll('<p><br></p>', '');
item.author = content('div.article-header-author div.author-link a.label').first().text();
item.category = item.category.filter(Boolean);
item.guid = `latepost-${item.guid}`;
const pubDate = content('div.article-header-date').text();
if (pubDate) {
item.pubDate = /\d+月\d+日/.test(pubDate) ? parseDate(pubDate, ['YYYY年MM月DD日 HH:mm', 'MM月DD日 HH:mm']) : parseRelativeDate(pubDate);
}
item.pubDate = timezone(item.pubDate, +8);
item.comments = commentResponse.data?.length() ?? 0;
return item;
})
)
);
const icon = new URL('favicon.ico', rootUrl).href;
const { data: currentResponse } = await got(currentUrl);
const $ = load(currentResponse);
return {
item: items,
title: `${title} - ${proma ? columns[proma].title : defaultTitle}`,
link: currentUrl,
description: $('div.logo-txt').first().text(),
language: 'zh-cn',
image: new URL($('div.logo-txt img').prop('src'), rootUrl).href,
icon,
logo: icon,
author: title,
};
}