diff --git a/lib/routes/zhihu/posts.ts b/lib/routes/zhihu/posts.ts index 29d971ef4..28f27ab23 100644 --- a/lib/routes/zhihu/posts.ts +++ b/lib/routes/zhihu/posts.ts @@ -1,8 +1,9 @@ import { Route } from '@/types'; import ofetch from '@/utils/ofetch'; +import cache from '@/utils/cache'; import { header, getSignedHeader, processImage } from './utils'; -import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; +import { Articles, Profile } from './types'; export const route: Route = { path: '/posts/:usertype/:id', @@ -34,15 +35,19 @@ async function handler(ctx) { const id = ctx.req.param('id'); const usertype = ctx.req.param('usertype'); - const data = await ofetch(`https://www.zhihu.com/${usertype}/${id}/posts`, { - headers: { - ...header, - Referer: `https://www.zhihu.com/${usertype}/${id}/`, - }, + const userProfile = await cache.tryGet(`zhihu:posts:profile:${id}`, async () => { + const userAPIPath = `/api/v4/${usertype === 'people' ? 'members' : 'org'}/${id}?${new URLSearchParams({ + include: 'allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics', + })}`; + + return await ofetch(`https://www.zhihu.com${userAPIPath}`, { + headers: { + ...header, + ...(await getSignedHeader(`https://www.zhihu.com/${usertype}/${id}/`, userAPIPath)), + Referer: `https://www.zhihu.com/${usertype}/${id}/`, + }, + }); }); - const $ = load(data); - const initialData = JSON.parse($('#js-initialData').text()); - const userData = initialData?.initialState?.entities?.users?.[id]; const apiPath = `/api/v4/${usertype === 'people' ? 'members' : 'org'}/${id}/articles?${new URLSearchParams({ include: @@ -54,7 +59,7 @@ async function handler(ctx) { const signedHeader = await getSignedHeader(`https://www.zhihu.com/${usertype}/${id}/posts`, apiPath); - const articleResponse = await ofetch(`https://www.zhihu.com${apiPath}`, { + const articleResponse = await ofetch(`https://www.zhihu.com${apiPath}`, { headers: { ...header, ...signedHeader, @@ -72,11 +77,11 @@ async function handler(ctx) { })); return { - title: `${userData?.name} 的知乎文章`, + title: `${userProfile.name} 的知乎文章`, link: `https://www.zhihu.com/${usertype}/${id}/posts`, - description: userData?.headline, - image: userData?.avatarUrlTemplate?.split('?')[0], - banner: userData?.coverUrl?.split('?')[0], + description: userProfile.headline, + image: userProfile.avatar_url.split('?')[0], + // banner: userData?.coverUrl?.split('?')[0], item: items, }; } diff --git a/lib/routes/zhihu/types.ts b/lib/routes/zhihu/types.ts new file mode 100644 index 000000000..7d685f5cc --- /dev/null +++ b/lib/routes/zhihu/types.ts @@ -0,0 +1,104 @@ +export interface Profile { + id: string; + url_token: string; + name: string; + use_default_avatar: boolean; + avatar_url: string; + avatar_url_template: string; + is_org: boolean; + type: string; + url: string; + user_type: string; + headline: string; + headline_render: string; + gender: number; + is_advertiser: boolean; + ip_info: string; + vip_info: { + is_vip: boolean; + vip_type: number; + rename_days: string; + entrance_v2: null; + rename_frequency: number; + rename_await_days: number; + }; + badge: any[]; + badge_v2: { + title: string; + merged_badges: any[]; + detail_badges: any[]; + icon: string; + night_icon: string; + }; + allow_message: boolean; + is_following: boolean; + is_followed: boolean; + is_blocking: boolean; + follower_count: number; + answer_count: number; + articles_count: number; + available_medals_count: number; + employments: any[]; + is_realname: boolean; + has_applying_column: boolean; +} + +interface Article { + image_url: string; + updated: number; + is_jump_native: boolean; + is_labeled: boolean; + copyright_permission: string; + vessay_info: { + enable_video_translate: boolean; + }; + excerpt: string; + admin_closed_comment: boolean; + article_type: string; + excerpt_title: string; + reaction_instruction: { + REACTION_CONTENT_SEGMENT_LIKE: string; + }; + id: number; + voteup_count: number; + upvoted_followees: []; + can_comment: { + status: boolean; + reason: string; + }; + author: Profile; + url: string; + comment_permission: string; + created: number; + image_width: number; + content: string; + comment_count: number; + linkbox: { + url: string; + category: string; + pic: string; + title: string; + }; + title: string; + voting: number; + type: string; + suggest_edit: { + status: boolean; + url: string; + reason: string; + tip: string; + title: string; + }; + is_normal: boolean; +} + +export interface Articles { + paging: { + is_end: boolean; + totals: number; + previous: string; + is_start: boolean; + next: string; + }; + data: Article[]; +}