feat(route): 得到用户主页 (#10993)

* feat(route): 得到用户主页

* fix typo

* fix: maintainer
This commit is contained in:
Ethan Shen 2022-10-05 20:34:23 +08:00 committed by GitHub
parent 8de58eeeb0
commit 4dbadfe2b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 316 additions and 101 deletions

View File

@ -1812,7 +1812,7 @@ Supported sub-sites:
### 首页
<Route author="nczitzk" example="/dedao/list/年度日更" path="/dedao/list/:caty?" :paramsDesc="['分类名,默认为年度日更']"/>
<Route author="nczitzk" example="/dedao/list/年度日更" path="/dedao/list/:category?" :paramsDesc="['分类名,默认为年度日更']"/>
### 新闻
@ -1828,7 +1828,17 @@ Supported sub-sites:
### 知识城邦
<Route author="nczitzk" example="/dedao/knowledge" path="/dedao/knowledge/:topic?/:type?" :paramsDesc="['话题 id可在话题页 URL 中找到', '分享类型,`true` 指精选,`false` 指最新,默认为精选']"/>
<Route author="nczitzk" example="/dedao/knowledge" path="/dedao/knowledge/:topic?/:type?" :paramsDesc="['话题 id可在对应话题页 URL 中找到', '分享类型,`true` 指精选,`false` 指最新,默认为精选']"/>
### 用户主页
<Route author="nczitzk" example="/dedao/user/VkA5OqLX4RyGxmZRNBMlwBrDaJQ9og" path="/dedao/user/:id/:type?" :paramsDesc="['用户 id可在对应用户主页 URL 中找到', '类型,见下表,默认为`0`,即动态']">
| 动态 | 书评 | 视频 |
| -- | -- | -- |
| 0 | 7 | 12 |
</Route>
## 电动邦

View File

@ -3353,9 +3353,9 @@ router.get('/nwpu/:column', lazyloadRouteHandler('./routes/nwpu/index'));
router.get('/us/supremecourt/argument_audio/:year?', lazyloadRouteHandler('./routes/us/supremecourt/argument_audio'));
// 得到
router.get('/dedao/list/:caty?', lazyloadRouteHandler('./routes/dedao/list'));
router.get('/dedao/knowledge/:topic?/:type?', lazyloadRouteHandler('./routes/dedao/knowledge'));
router.get('/dedao/:caty?', lazyloadRouteHandler('./routes/dedao/index'));
// router.get('/dedao/list/:caty?', lazyloadRouteHandler('./routes/dedao/list'));
// router.get('/dedao/knowledge/:topic?/:type?', lazyloadRouteHandler('./routes/dedao/knowledge'));
// router.get('/dedao/:caty?', lazyloadRouteHandler('./routes/dedao/index'));
// 未名新闻
router.get('/mitbbs/:caty?', lazyloadRouteHandler('./routes/mitbbs/index'));

View File

@ -1,78 +0,0 @@
const got = require('@/utils/got');
const date = require('@/utils/date');
module.exports = async (ctx) => {
const topic = ctx.params.topic || '';
const type = ctx.params.type || 'true';
const rootUrl = 'https://www.dedao.cn';
const detailUrl = `${rootUrl}/pc/ledgers/topic/detail`;
const currentUrl = `${rootUrl}/knowledge${topic === '' ? '' : '/topic/' + topic}`;
const apiUrl = `${rootUrl}/pc/ledgers/${topic === '' ? 'notes/friends_timeline' : 'topic/notes/list'}`;
let title = '',
description = '';
if (topic !== '') {
const detailResponse = await got({
method: 'post',
url: detailUrl,
json: {
incr_view_count: false,
topic_id_hazy: topic,
},
});
title = detailResponse.data.c.name;
description = detailResponse.data.c.intro;
}
const response = await got({
method: 'post',
url: apiUrl,
json: {
count: 20,
load_chain: true,
is_elected: type === 'true',
page_id: 0,
topic_id_hazy: topic,
version: 2,
},
});
const items = (topic === '' ? response.data.c.notes : response.data.c.note_detail_list).map((item) => {
let s_part = '';
if (item.s_part) {
const s_author = `<p>引用 ${item.s_part.nick_name} (${item.s_part.v_info}):</p>`;
const s_content = `<p>${item.s_part.note.replace(/\n\n/g, '</p><p>')}</p> <a href="${rootUrl}/knowledge/note/${item.s_part.note_id_hazy}">[查看原文]</a>`;
let s_images = '<br>';
if (item.s_part.images) {
for (const i of item.s_part.images) {
s_images += `<img src="${i.match(/"url":"(.*)"/)[1]}">`;
}
}
s_part = s_author + s_content + s_images;
}
let f_images = '<br>';
if (item.f_part.images) {
for (const i of item.f_part.images) {
f_images += `<img src="${i.match(/"url":"(.*)"/)[1]}">`;
}
}
return {
title: item.f_part.note,
author: item.f_part.nick_name,
description: `<p>${item.f_part.note.replace(/\n\n/g, '</p><p>')}</p>${f_images}<br>${s_part}`,
link: `${rootUrl}/knowledge/note/${item.f_part.note_id_hazy}`,
pubDate: new Date(date(item.f_part.time_desc)).toUTCString(),
};
});
ctx.state.data = {
title: `得到 - 知识城邦${title === '' ? '' : ' - ' + title}`,
link: currentUrl,
item: items,
description,
};
};

View File

@ -1,9 +1,11 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const caty = ctx.params.caty || 'news';
const rootUrl = `https://www.igetget.com/${caty === 'video' ? 'video' : 'news'}`;
const category = ctx.params.category ?? 'news';
const rootUrl = `https://www.igetget.com/${category === 'video' ? 'video' : 'news'}`;
const response = await got({
method: 'get',
@ -12,19 +14,20 @@ module.exports = async (ctx) => {
const data = JSON.parse(response.data.match(/window.__INITIAL_STATE__= (.*);<\/script>/)[1]);
const list = (caty === 'news' ? data.news : caty === 'figure' ? data.figure : data.videoList).map((item) => ({
let items = (category === 'news' ? data.news : category === 'figure' ? data.figure : data.videoList).map((item) => ({
title: item.title,
pubDate: new Date(item.online_time).toUTCString(),
link: `${rootUrl}/${caty === 'news' ? 'article/' : caty === 'figure' ? 'people/' : ''}${item.online_time.split('T')[0].split('-').join('')}/${item.token}`,
pubDate: parseDate(item.online_time),
link: `${rootUrl}/${category === 'news' ? 'article/' : category === 'figure' ? 'people/' : ''}${item.online_time.split('T')[0].split('-').join('')}/${item.token}`,
}));
const items = await Promise.all(
list.map((item) =>
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
item.description = content('.menu-article').html();
@ -35,7 +38,7 @@ module.exports = async (ctx) => {
);
ctx.state.data = {
title: `得到${caty === 'video' ? '' : '大事件'} - ${caty === 'news' ? '新闻' : caty === 'figure' ? '人物故事' : '视频'}`,
title: `得到${category === 'video' ? '' : '大事件'} - ${category === 'news' ? '新闻' : category === 'figure' ? '人物故事' : '视频'}`,
link: rootUrl,
item: items,
description: data.description,

64
lib/v2/dedao/knowledge.js Normal file
View File

@ -0,0 +1,64 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
module.exports = async (ctx) => {
const topic = ctx.params.topic ?? '';
const type = /t|y/i.test(ctx.params.type ?? 'true');
const count = ctx.query.limit ? parseInt(ctx.query.limit) : 100;
const rootUrl = 'https://www.dedao.cn';
const currentUrl = `${rootUrl}/knowledge${topic === '' ? '' : '/topic/' + topic}`;
const apiUrl = `${rootUrl}/pc/ledgers/${topic === '' ? 'notes/friends_timeline' : 'topic/notes/list'}`;
const detailUrl = `${rootUrl}/pc/ledgers/topic/detail`;
let title = '',
description = '';
if (topic !== '') {
const detailResponse = await got({
method: 'post',
url: detailUrl,
json: {
incr_view_count: false,
topic_id_hazy: topic,
},
});
title = detailResponse.data.c.name;
description = detailResponse.data.c.intro;
}
const response = await got({
method: 'post',
url: apiUrl,
json: {
count,
load_chain: true,
is_elected: type,
page_id: 0,
topic_id_hazy: topic,
version: 2,
},
});
const items = (topic === '' ? response.data.c.notes : response.data.c.note_detail_list).map((item) => ({
title: item.f_part.note,
author: item.f_part.nick_name,
link: `${rootUrl}/knowledge/note/${item.f_part.note_id_hazy}`,
pubDate: parseDate(item.f_part.time_desc, 'MM-DD'),
description: art(path.join(__dirname, 'templates/knowledge.art'), {
rootUrl,
f_part: item.f_part,
s_part: item.s_part,
}),
}));
ctx.state.data = {
title: `得到 - 知识城邦${title === '' ? '' : ' - ' + title}`,
link: currentUrl,
item: items,
description,
};
};

View File

@ -2,20 +2,24 @@ const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const caty = ctx.params.caty || '年度日更';
const category = ctx.params.category ?? '年度日更';
const rootUrl = 'https://www.igetget.com';
const response = await got({
method: 'get',
url: rootUrl,
});
const listUrl = `${rootUrl}${response.data.match(new RegExp('<a href="(.*)">年度日更<\\/a>'))[1]}`;
const listResponse = await got({
method: 'get',
url: listUrl,
});
const currentUrl = `${rootUrl}${listResponse.data.match(new RegExp('<span>' + caty + '<\\/span><a href="(.*)" rel="tag"><\\/a>'))[1].split('"')[0]}`;
const currentUrl = `${rootUrl}${listResponse.data.match(new RegExp('<span>' + category + '<\\/span><a href="(.*)" rel="tag"><\\/a>'))[1].split('"')[0]}`;
const currentResponse = await got({
method: 'get',
url: currentUrl,
@ -23,24 +27,26 @@ module.exports = async (ctx) => {
const $ = cheerio.load(currentResponse.data);
const list = $('.pro-info p a')
.slice(0, 10)
.map((_, item) => {
let items = $('.pro-info p a')
.toArray()
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 10)
.map((item) => {
item = $(item);
return {
title: item.text(),
link: `${rootUrl}${item.attr('href')}`,
};
})
.get();
});
const items = await Promise.all(
list.map((item) =>
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
content('.more-bt').remove();
@ -53,7 +59,7 @@ module.exports = async (ctx) => {
);
ctx.state.data = {
title: `得到 - ${caty}`,
title: `得到 - ${category}`,
link: currentUrl,
item: items,
};

View File

@ -0,0 +1,8 @@
module.exports = {
'/figure': ['nczitzk'],
'/knowledge/:topic?/:type?': ['nczitzk'],
'/list/:category?': ['nczitzk'],
'/news': ['nczitzk'],
'/user/:id/:type?': ['nczitzk'],
'/video': ['nczitzk'],
};

50
lib/v2/dedao/radar.js Normal file
View File

@ -0,0 +1,50 @@
module.exports = {
'dedao.cn': {
_name: '得到',
'.': [
{
title: '知识城邦',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-zhi-shi-cheng-bang',
source: ['/knowledge/topic/:topic', '/knowledge', '/'],
target: '/dedao/knowledge/:topic?/:type?',
},
],
},
'igetget.com': {
_name: '得到',
'.': [
{
title: '首页',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-shou-ye',
source: ['/'],
target: '/dedao/list/:category?',
},
{
title: '新闻',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-xin-wen',
source: ['/news', '/'],
target: '/dedao/news',
},
{
title: '人物故事',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-ren-wu-gu-shi',
source: ['/news', '/'],
target: '/dedao/figure',
},
{
title: '视频',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-shi-pin',
source: ['/video', '/'],
target: '/dedao/video',
},
],
m: [
{
title: '用户主页',
docs: 'https://docs.rsshub.app/new-media.html#de-dao-yong-hu-zhu-ye',
source: ['/native/mine/account', '/'],
target: (params, url) => `/dedao/user/${new URL(url).searchParams.get('enId')}`,
},
],
},
};

6
lib/v2/dedao/router.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = function (router) {
router.get('/knowledge/:topic?/:type?', require('./knowledge'));
router.get('/list/:category?', require('./list'));
router.get('/user/:id/:type?', require('./user'));
router.get('/:category?', require('./index'));
};

View File

@ -0,0 +1,29 @@
{{ if f_part.note }}
<p>{{@ f_part.note
.replace(/\n\n/g, '</p><p>')
.replace(/<≧❆>{"name":"(.*?)","uid":"\d+","at":"1"}<\/≦❆>/g, ' @$1')
}}</p>
{{ /if }}
{{ if f_part.images }}
<br>
{{ set f_part_images = f_part.images }}
{{ each f_part_images image }}
<img src="{{ image.match(/"url":"(.*?)"/)[1] }}">
{{ /each }}
{{ /if }}
{{ if s_part }}
<br>
<p>引用 {{ s_part.nick_name }}{{ if s_part.v_info }} ({{ s_part.v_info }}){{ /if }}:</p>
<p>{{@ s_part.note
.replace(/\n\n/g, '</p><p>')
.replace(/<≧❆>{"name":"(.*?)","uid":"\d+","at":"1"}<\/≦❆>/g, ' @$1')
}}</p>
<a href="{{ rootUrl }}/knowledge/note/{{ s_part.note_id_hazy }}">[查看原文]</a>
{{ if s_part.images }}
<br>
{{ set s_part_images = s_part.images }}
{{ each s_part_images image}}
<img src="{{ image.match(/"url":"(.*?)"/)[1] }}">
{{ /each }}
{{ /if }}
{{ /if }}

View File

@ -0,0 +1,38 @@
{{ if name }}
<p>{{@ content
.replace(/\n\n/g, '</p><p>')
.replace(/<≧❆>{"name":"(.*?)","uid":"\d+","at":"1"}<\/≦❆>/g, ' @$1')
}}</p>
<br>
<p>引用 {{ name }}{{ if vinfo }} ({{ vinfo }}){{ /if }}:</p>
{{ /if }}
<p>{{@ note
.replace(/\n\n/g, '</p><p>')
.replace(/<≧❆>{"name":"(.*?)","uid":"\d+","at":"1"}<\/≦❆>/g, ' @$1')
}}</p>
{{ if extra }}
<br>
{{ if extra.img }}
{{ if extra.share_ext }}
<a href="{{ extra.share_ext.h_5_url }}">
{{ /if }}
<figure>
<img src="{{ extra.img }}">
<figcaption>{{ extra.title }}</figcaption>
</figure>
{{ if extra.share_ext }}
</a>
{{ /if }}
{{ /if }}
{{ if extra.images }}
{{ set extra_images = extra.images }}
{{ each extra_images image }}
<img src="{{ image.match(/"url":"(.*?)"/)[1] }}">
{{ /each }}
{{ /if }}
{{ if video }}
<figure>
<img src="{{ video.match(/"url":"(.*?)"/)[1] }}">
</figure>
{{ /if }}
{{ /if }}

79
lib/v2/dedao/user.js Normal file
View File

@ -0,0 +1,79 @@
const got = require('@/utils/got');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
const types = {
0: '动态',
7: '书评',
12: '视频',
};
module.exports = async (ctx) => {
const id = ctx.params.id ?? '';
const type = ctx.params.type ? parseInt(ctx.params.type) : 0;
const count = ctx.query.limit ? parseInt(ctx.query.limit) : 100;
const rootUrl = 'https://m.igetget.com';
const currentUrl = `${rootUrl}/native/mine/account#/user/detail?enId=${id}`;
const apiUrl = `${rootUrl}/native/api/homePage/topicNote`;
const infoUrl = `${rootUrl}/native/api/homePage/userInfo`;
const detailResponse = await got({
method: 'post',
url: infoUrl,
json: {
hazy: id,
},
});
const data = detailResponse.data;
const author = data.c.nickname;
const image = data.c.avatar;
const description = `${data.c.v_info}: ${data.c.slogan}`;
const response = await got({
method: 'post',
url: apiUrl,
json: {
uid: null,
max_id_str: '0',
count,
max_createtime: 0,
is_only_repost: 0,
load_chain: true,
load_tag: 1,
source: 0,
note_type: type,
only_origin: false,
with_highlight: true,
hazy: id,
},
});
const items = response.data.c.list.map((item) => ({
author,
title: item.content || item.note || item.extra.title,
link: item.share_url,
pubDate: parseDate(item.create_time * 1000),
description: art(path.join(__dirname, 'templates/user.art'), {
rootUrl,
name: item.origin_notes_owner.name,
vinfo: item.origin_notes_owner.Vinfo,
content: item.content,
note: item.note,
extra: item.extra,
video: item.video.video_cover,
}),
}));
ctx.state.data = {
title: `${author}的得到主页 - ${types[type]}`,
link: currentUrl,
item: items,
image,
description,
allowEmpty: true,
};
};