diff --git a/lib/routes/now/news.ts b/lib/routes/now/news.ts index 1f6b7f05f7..070ad375f7 100644 --- a/lib/routes/now/news.ts +++ b/lib/routes/now/news.ts @@ -1,9 +1,18 @@ import { Route } from '@/types'; import cache from '@/utils/cache'; -import got from '@/utils/got'; +import ofetch from '@/utils/ofetch'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; +const mainCategories = { + local: 119, + international: 120, + entertainment: 500, + life: 501, + technology: 502, + finance: 121, +}; + const categories = { tracker: 123, feature: 124, @@ -25,7 +34,8 @@ export const route: Route = { }, radar: [ { - source: ['news.now.com/'], + source: ['news.now.com/home/:category?', 'news.now.com/'], + target: '/news/:category?', }, ], name: '新聞', @@ -52,44 +62,94 @@ export const route: Route = { }; async function handler(ctx) { - const category = ctx.req.param('category') || ''; - const id = ctx.req.param('id') || ''; + const { category = '', id = '' } = ctx.req.param(); + const limit = Number.parseInt(ctx.req.query('limit') || '20', 10); + const hasTopicId = id && Object.hasOwn(categories, category); const rootUrl = 'https://news.now.com'; - const currentUrl = Object.hasOwn(categories, category) ? `${rootUrl}/home/${category}/detail?catCode=${categories[category]}&topicId=${id}` : `${rootUrl}/home${category ? `/${category}` : ''}`; + const pageUrl = hasTopicId ? `${rootUrl}/home/${category}/detail?catCode=${categories[category]}&topicId=${id}` : `${rootUrl}/home${category ? `/${category}` : ''}`; - const response = await got({ - method: 'get', - url: currentUrl, - }); + let apiUrl; + if (hasTopicId) { + apiUrl = pageUrl; + } else if (category === 'sports') { + apiUrl = `https://sportsapi.now.com/api/getNewsList?pageSize=${limit}&pageNo=1&searchTagsKey=allSportsSearchTags`; + } else if (category) { + apiUrl = `https://d3sli7vh0lsda4.cloudfront.net/api/getNewsList?category=${mainCategories[category]}&pageNo=1&pageSize=${limit}`; + } else { + apiUrl = pageUrl; + } - const $ = load(response.data); + const response = await ofetch(apiUrl); + const isApi = typeof response === 'object' && Array.isArray(response); + const $ = load(response); - const list = $(`${category === '' ? '.homeFeaturedNews ' : '.newsCategoryColLeft '}.newsTitle`) - .toArray() - .map((item) => { - item = $(item); + let list; + if (isApi) { + list = + category === 'sports' + ? response.map((item) => { + const image = item.newsPhotos + ?.filter((p) => p.sizeType === '3') + ?.map((p) => ``) + .join(''); + return { + title: item.headlineChi, + description: image, + link: `https://news.now.com/home/${category}/player?newsId=${item.newsId}`, + pubDate: parseDate(item.publishDate, 'x'), + category: [...item.sportTypes.map((t) => t.sportTypeNameChi), ...item.players.map((p) => p.playerFullNameChi), ...item.teams.map((t) => t.teamCodeChi)], + image: item.newsPhotos?.filter((p) => p.sizeType === '3')?.[0]?.imageUrl, + newsId: item.newsId, + }; + }) + : response.map((item) => { + const image = item.image2Url ?? item.imageUrl ?? item.image3Url; + return { + title: item.title, + description: (image ? `` : '') + item.leading + item.summary, + link: `https://news.now.com/home/${category}/player?newsId=${item.newsId}`, + pubDate: parseDate(item.publishDate, 'x'), + updated: parseDate(item.lastModifyDate, 'x'), + category: item.newsTags.map((t) => t.tag), + image, + }; + }); + } else { + list = $(`${category === '' ? '.homeFeaturedNews ' : '.newsCategoryColLeft '}.newsTitle`) + .toArray() + .slice(0, limit) + .map((item) => { + item = $(item); - return { - title: item.text(), - link: `${rootUrl}${item.parent().parent().attr('href')}`, - }; - }); + return { + title: item.text(), + link: `${rootUrl}${item.parent().parent().attr('href')}`, + }; + }); + } const items = await Promise.all( list.map((item) => cache.tryGet(item.link, async () => { - const detailResponse = await got({ - method: 'get', - url: item.link, - }); - const content = load(detailResponse.data); + if (!item.pubDate || item.newsId) { + const detailResponse = await ofetch(item.link); + const $ = load(detailResponse); - const images = detailResponse.data.match(/"imageUrl":"(.*?)","image2Url":/); + const newsData = JSON.parse( + $('script:contains("var newsData")') + .text() + .match(/var newsData = (.*?);/)?.[1] || '{}' + ); - item.pubDate = parseDate(content('.published').attr('datetime')); - item.description = (images ? `` : '') + content('.newsLeading').html(); + const images = newsData.imageList ? newsData.imageList.map((img) => ``).join('') : ''; + + item.description = item.description ? item.description + ($('.img_caption').prop('outerHTML') ?? '') + $('.newsLeading').html() : images + $('.newsLeading').html(); + item.pubDate ||= parseDate(newsData.publishDate, 'x'); + item.updated ||= parseDate(newsData.lastModifyDate, 'x'); + item.category ||= [...new Set([newsData.categoryName, ...newsData.newsTags.map((t) => t.tag), ...newsData.newsTopics.map((t) => t.topicName)])]; + } return item; }) @@ -97,8 +157,8 @@ async function handler(ctx) { ); return { - title: String(Object.hasOwn(categories, category) ? $('title').text() : ($('.smallSpace.active').text() || '首頁') + ' | Now 新聞'), - link: currentUrl, + title: Object.hasOwn(categories, category) ? $('title').text() : ($('.smallSpace.active').text() || '首頁') + ' | Now 新聞', + link: pageUrl, item: items, }; }