const got = require('@/utils/got'); const cheerio = require('cheerio'); const timezone = require('@/utils/timezone'); const { parseDate, parseRelativeDate } = require('@/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) => arr.reduce( (dictionary, { id, ...rest }) => ({ ...dictionary, [id]: { ...rest, }, }), {} ); module.exports = async (ctx) => { const { proma } = ctx.params; const limit = ctx.query.limit ? parseInt(ctx.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: 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) => ctx.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 = cheerio.load(detailResponse); item.title = item.title ?? content('div.article-header-title').text(); item.description = content('#select-main') .html() .replace(/


<\/p>/g, ''); item.author = content('div.article-header-author div.author-link a.label').first().text(); item.category = item.category.filter((c) => c); item.guid = `latepost-${item.guid}`; const pubDate = content('div.article-header-date').text(); if (pubDate) { if (/\d+月\d+日/.test(pubDate)) { item.pubDate = parseDate(pubDate, ['MM月DD日 HH:mm', 'YYYY年MM月DD日 HH:mm']); } else { item.pubDate = 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 $ = cheerio.load(currentResponse); ctx.state.data = { 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, }; };