Skip to content

Commit

Permalink
feat: add an router for getting all collections of a user in zhihu.co…
Browse files Browse the repository at this point in the history
…m. (#18028)

* 添加知乎路由,用于获取指定用户所有公开的收藏内容

* 修改example地址

* 修改代码以符合路由规范

* Update lib/routes/zhihu/all-collections.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* 修改代码以符合路由规范和代码审阅者要求的got请求代码格式统一和re-cast的问题

---------

Co-authored-by: yuerongkang <yuerongkang@drivedream.com>
  • Loading branch information
Healthyyue and yuerongkang authored Jan 6, 2025
1 parent 1e246f2 commit c405ee8
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 0 deletions.
109 changes: 109 additions & 0 deletions lib/routes/zhihu/all-collections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Route, ViewType, Collection, CollectionItem } from '@/types';
import got from '@/utils/got';
import { header } from './utils';
import { parseDate } from '@/utils/parse-date';
import cache from '@/utils/cache';

export const route: Route = {
path: '/people/allCollections/:id',
categories: ['social-media'],
view: ViewType.Articles,
example: '/zhihu/people/allCollections/87-44-49-67',
parameters: { id: '作者 id,可在用户主页 URL 中找到' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.zhihu.com/people/:id'],
// target: 'people/allCollections/:id',
},
],
name: '用户全部收藏内容',
maintainers: ['Healthyyue'],
handler,
};

async function handler(ctx) {
const id = ctx.req.param('id');
const apiPath = `https://api.zhihu.com/people/${id}/collections`;

const response = await got(apiPath, {
headers: {
Referer: `https://www.zhihu.com/people/${id}/collections`,
},
});

const collections = response.data.data as Collection[];

const allCollectionItems = await Promise.all(
collections.map(async (collection) => {
const firstPageResponse = await got(`https://www.zhihu.com/api/v4/collections/${collection.id}/items?offset=0&limit=20`, {
headers: {
...header,
Referer: `https://www.zhihu.com/collection/${collection.id}`,
},
});

const {
data: items,
paging: { totals },
} = firstPageResponse.data;

if (totals > 20) {
const offsetList = Array.from({ length: Math.ceil(totals / 20) - 1 }, (_, index) => (index + 1) * 20);

const otherPages = await Promise.all(
offsetList.map((offset) =>
cache.tryGet(`https://www.zhihu.com/api/v4/collections/${collection.id}/items?offset=${offset}&limit=20`, async () => {
const response = await got(`https://www.zhihu.com/api/v4/collections/${collection.id}/items?offset=${offset}&limit=20`, {
headers: {
...header,
Referer: `https://www.zhihu.com/collection/${collection.id}`,
},
});
return response.data.data;
})
)
);

items.push(...otherPages.flat());
}

return {
collectionId: collection.id,
collectionTitle: collection.title,
items,
};
})
);

const items = allCollectionItems.flatMap(
(collection) =>
collection.items.map((item) => ({
...item,
collectionTitle: collection.collectionTitle,
})) as CollectionItem[]
);

return {
title: `${collections[0].creator.name}的知乎收藏`,
link: `https://www.zhihu.com/people/${id}/collections`,
item: items.map((item) => {
const content = item.content;

return {
title: content.type === 'article' || content.type === 'zvideo' ? content.title : content.question.title,
link: content.url,
description: content.type === 'zvideo' ? `<img src=${content.video.url}/>` : content.content,
pubDate: parseDate((content.type === 'article' ? content.updated : content.updated_time) * 1000),
category: [item.collectionTitle],
};
}),
};
}
26 changes: 26 additions & 0 deletions lib/routes/zhihu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,29 @@ export interface Articles {
};
data: Article[];
}

export interface CollectionItem {
content: {
type: string;
title?: string;
question?: {
title: string;
};
url: string;
content: string;
video?: {
url: string;
};
updated?: number;
updated_time?: number;
};
collectionTitle?: string;
}

export interface Collection {
id: string;
title: string;
creator: {
name: string;
};
}

0 comments on commit c405ee8

Please sign in to comment.