diff --git a/lib/routes/thepaper/channel.ts b/lib/routes/thepaper/channel.ts index 96fccb26d01aa1..11d66cf2a7f2bd 100644 --- a/lib/routes/thepaper/channel.ts +++ b/lib/routes/thepaper/channel.ts @@ -5,7 +5,7 @@ import got from '@/utils/got'; export const route: Route = { path: '/channel/:id', - categories: ['traditional-media'], + categories: ['new-media'], example: '/thepaper/channel/25950', parameters: { id: '频道 id,可在频道页 URL 中找到' }, features: { diff --git a/lib/routes/thepaper/factpaper.ts b/lib/routes/thepaper/factpaper.ts index 44639088b07e04..c5623f23908f94 100644 --- a/lib/routes/thepaper/factpaper.ts +++ b/lib/routes/thepaper/factpaper.ts @@ -11,7 +11,7 @@ import path from 'node:path'; export const route: Route = { path: '/factpaper/:status?', - categories: ['traditional-media'], + categories: ['new-media'], example: '/thepaper/factpaper', parameters: { status: '状态 id,可选 `1` 即 有定论 或 `0` 即 核查中,默认为 `1`' }, features: { diff --git a/lib/routes/thepaper/featured.ts b/lib/routes/thepaper/featured.ts index b660d38f4d62a7..1f4127e49b2ae1 100644 --- a/lib/routes/thepaper/featured.ts +++ b/lib/routes/thepaper/featured.ts @@ -5,7 +5,7 @@ import got from '@/utils/got'; export const route: Route = { path: '/featured', - categories: ['traditional-media'], + categories: ['new-media'], example: '/thepaper/featured', parameters: {}, features: { diff --git a/lib/routes/thepaper/list.ts b/lib/routes/thepaper/list.ts index 16dd6f74951319..26c0293925761b 100644 --- a/lib/routes/thepaper/list.ts +++ b/lib/routes/thepaper/list.ts @@ -5,7 +5,7 @@ import got from '@/utils/got'; export const route: Route = { path: '/list/:id', - categories: ['traditional-media'], + categories: ['new-media'], example: '/thepaper/list/25457', parameters: { id: '栏目 id,可在栏目页 URL 中找到' }, features: { diff --git a/lib/routes/thepaper/user.ts b/lib/routes/thepaper/user.ts new file mode 100644 index 00000000000000..d072f002484ff8 --- /dev/null +++ b/lib/routes/thepaper/user.ts @@ -0,0 +1,174 @@ +import { Route } from '@/types'; +import * as cheerio from 'cheerio'; +import ofetch from '@/utils/ofetch'; +import cache from '@/utils/cache'; +import { parseDate } from '@/utils/parse-date'; + +export const route: Route = { + path: '/user/:pphId', + categories: ['new-media'], + example: '/thepaper/user/4221423', + parameters: { pphId: '澎湃号 id,可在澎湃号页 URL 中找到' }, + name: '澎湃号', + maintainers: ['TonyRL'], + handler, +}; + +interface AuthorInfo { + userId: number; + sname: string; + pic: string; + isAuth: string; + userType: string; + perDesc: string; + mobile: null; + isOrder: string; + sex: string; + area: string; + attentionNum: string; + fansNum: string; + praiseNum: null; + pph: boolean; + normalUser: boolean; + mobForwardType: number; + authInfo: string; + mail: string; + pphImpactNum: string; + wonderfulCommentCount: string; + location: string; + lastLoginDate: null; +} + +interface PPHContentResponse { + code: number; + data: Data; + desc: string; + time: number; +} + +interface Data { + hasNext: boolean; + startTime: number; + list: ListItem[]; + nodeInfo: null; + tagInfo: null; + moreNodeInfo: null; + pageNum: null; + pageSize: null; + pages: null; + total: null; + prevPageNum: null; + nextPageNum: null; + excludeContIds: null; + contCont: null; + filterIds: null; + updateCount: null; +} + +interface ListItem { + contId: string; + isOutForword: string; + isOutForward: string; + forwardType: string; + mobForwardType: number; + interactionNum: string; + praiseTimes: string; + pic: string; + imgCardMode: number; + smallPic: string; + sharePic: string; + pubTime: string; + pubTimeNew: string; + name: string; + closePraise: string; + authorInfo: AuthorInfo; + nodeId: number; + contType: number; + pubTimeLong: number; + specialNodeId: number; + cardMode: string; + dataObjId: number; + closeFrontComment: boolean; + isSupInteraction: boolean; + hideVideoFlag: boolean; + praiseStyle: number; + isSustainedFly: number; + softLocType: number; + closeComment: boolean; + voiceInfo: VoiceInfo; + softAdTypeStr: string; +} + +interface VoiceInfo { + imgSrc: string; + isHaveVoice: string; +} + +async function handler(ctx) { + const { pphId } = ctx.req.param(); + + const mobileBuildId = (await cache.tryGet('thepaper:m:buildId', async () => { + const response = await ofetch('https://m.thepaper.cn'); + const $ = cheerio.load(response); + const nextData = JSON.parse($('script#__NEXT_DATA__').text()); + return nextData.buildId; + })) as string; + + const userInfo = (await cache.tryGet(`thepaper:user:${pphId}`, async () => { + const response = await ofetch(`https://api.thepaper.cn/userservice/user/homePage/${pphId}`, { + headers: { + 'Client-Type': '2', + Origin: 'https://m.thepaper.cn', + Referer: 'https://m.thepaper.cn/', + }, + }); + return response.userInfo; + })) as AuthorInfo; + + const response = await ofetch('https://api.thepaper.cn/contentapi/cont/pph/user', { + method: 'POST', + body: { + pageSize: 10, + pageNum: 1, + contType: 0, + excludeContIds: [], + pphId, + startTime: 0, + }, + }); + + const list = response.data.list.map((item) => ({ + title: item.name, + link: `https://www.thepaper.cn/newsDetail_forward_${item.contId}`, + pubDate: parseDate(item.pubTimeLong), + author: item.authorInfo.sname, + contId: item.contId, + image: item.pic, + })); + + const items = await Promise.all( + list.map((item) => + cache.tryGet(item.link, async () => { + const response = await ofetch(`https://m.thepaper.cn/_next/data/${mobileBuildId}/detail/${item.contId}.json`, { + query: { + id: item.contId, + }, + }); + + item.description = response.pageProps.detailData.contentDetail.content; + item.updated = parseDate(response.pageProps.detailData.contentDetail.updateTime); + + return item; + }) + ) + ); + + return { + title: userInfo.sname, + description: userInfo.perDesc, + link: `https://www.thepaper.cn/user_${pphId}`, + item: items, + itunes_author: userInfo.sname, + image: userInfo.pic, + }; +}