feat(route): add 后续 (#8470)

* feat(route): add 后续

* fix: set limit to 30

* fix typo
This commit is contained in:
Ethan Shen 2022-02-02 03:28:30 +08:00 committed by GitHub
parent b6a36f1e61
commit c9ccd6bb9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 136 deletions

View File

@ -1780,20 +1780,20 @@ others = 热点新闻 + 滚动新闻
## 后续
### Live
### 分类
<Route author="ciaranchen sanmmm" example="/houxu/live/5" path="/houxu/live/:id" :paramsDesc="['Live ID']" />
<Route author="nczitzk" example="/houxu" path="/houxu/:category?" :paramsDesc="['分类,见下表,默认为首页']">
### 最新 Live
<Route author="ciaranchen" example="/houxu/lives/new" path="/houxu/lives/:type" :paramsDesc="['类型']">
| 往事进展 | 最新添加 |
| -------- | -------- |
| realtime | new |
| 首页 | 热点 | 跟踪 | 事件 |
| ----- | -------- | ------ | ------ |
| index | featured | memory | events |
</Route>
### Lives
<Route author="ciaranchen sanmmm nczitzk" example="/houxu/lives/33899" path="/houxu/:category?" :paramsDesc="['编号,可在对应 Live 页面的 URL 中找到']"/>
### 最新专栏
<Route author="ciaranchen" example="/houxu/events" path="/houxu/events"/>

View File

@ -1002,9 +1002,9 @@ router.get('/miniapp/article/:category', lazyloadRouteHandler('./routes/miniapp/
router.get('/miniapp/store/newest', lazyloadRouteHandler('./routes/miniapp/store/newest'));
// 后续
router.get('/houxu/live/:id/:timeline?', lazyloadRouteHandler('./routes/houxu/live'));
router.get('/houxu/events', lazyloadRouteHandler('./routes/houxu/events'));
router.get('/houxu/lives/:type', lazyloadRouteHandler('./routes/houxu/lives'));
// router.get('/houxu/live/:id/:timeline?', lazyloadRouteHandler('./routes/houxu/live'));
// router.get('/houxu/events', lazyloadRouteHandler('./routes/houxu/events'));
// router.get('/houxu/lives/:type', lazyloadRouteHandler('./routes/houxu/lives'));
// 老司机
router.get('/laosiji/hot', lazyloadRouteHandler('./routes/laosiji/hot'));

View File

@ -1,27 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const baseUrl = `https://houxu.app/events`;
const res = await got.get(baseUrl);
const $ = cheerio.load(res.data);
const list = $('div.list > div');
const descriptionSelector = '.summary';
const out = list
.map((_, el) => {
const each = $(el);
return {
title: each.find('a').first().text().trim() + ' | ' + each.find('h3').text().trim(),
description: each.find(descriptionSelector).text().trim(),
link: 'https://houxu.app' + each.find('a').first().attr('href'),
};
})
.get();
ctx.state.data = {
title: $('title').text().trim(),
description: $('title').text().trim(),
link: baseUrl,
item: out,
};
};

View File

@ -1,39 +0,0 @@
const got = require('@/utils/got');
module.exports = async (ctx) => {
const { id } = ctx.params;
const baseUrl = 'https://houxu.app';
const baseInfoApi = `${baseUrl}/api/1/lives/${id}`;
const { desc, title } = await ctx.cache.tryGet(baseInfoApi, async () => {
const res = await got.get(baseInfoApi);
const { summary: desc, title } = res.data;
return {
title,
desc,
};
});
const itemsRes = await got(`${baseUrl}/api/1/lives/${id}/threads`, {
searchParams: {
limit: 40,
},
});
const item = itemsRes.data.results.map((i) => {
const { media, url, title, description, publish_at } = i.link;
return {
title,
description: `${description}<br/><img src="${media.avatar_url}" />`,
link: url,
pubDate: new Date(publish_at).toUTCString(),
author: media.name,
};
});
ctx.state.data = {
title,
description: desc,
link: `${baseUrl}/lives/${id}`,
item,
};
};

View File

@ -1,58 +0,0 @@
const got = require('@/utils/got');
const getLiveUrlById = (liveId) => `https://houxu.app/lives/${liveId}`;
const realtimeHandler = async () => {
const res = await got.get('https://houxu.app/api/1/lives/updated/');
const out = res.data.results.map((el) => ({
title: el.last.link.title,
description: el.last.link.description,
author: el.last.link.media ? el.last.link.media.name : null,
link: getLiveUrlById(el.id),
guid: 'realtime-' + el.id + '-' + el.last.id,
pubDate: new Date(el.news_update_at).toUTCString(),
}));
return {
title: '往事进展 - 后续',
description: 'Live 往事进展',
link: 'https://houxu.app/lives/realtime',
item: out,
};
};
const newHandler = async () => {
const res = await got.get('https://houxu.app/api/1/records/index/');
const out = res.data.results
.filter((el) => el.type === 'live')
.map((el) => ({
title: el.object.title,
description: el.object.summary,
link: getLiveUrlById(el.object.id),
guid: 'new-' + el.object.id,
pubDate: new Date(el.publish_at).toUTCString(),
}));
return {
title: '最新添加 - 后续',
description: 'Live 最新添加',
link: 'https://houxu.app/lives/new',
item: out,
};
};
module.exports = async (ctx) => {
const { type } = ctx.params;
switch (type) {
case 'realtime':
ctx.state.data = await realtimeHandler();
break;
case 'new':
ctx.state.data = await newHandler();
break;
default:
ctx.throw(404, 'Unknown lives type');
return;
}
};

85
lib/v2/houxu/index.js Normal file
View File

@ -0,0 +1,85 @@
const got = require('@/utils/got');
const path = require('path');
const { art } = require('@/utils/render');
const { parseDate } = require('@/utils/parse-date');
const categories = {
index: '首页',
featured: '热点',
updated: '跟踪',
memory: '跟踪',
events: '事件',
};
module.exports = async (ctx) => {
const category = ctx.params.category ?? 'index';
const id = ctx.params.id ?? '';
let title,
description,
author = '';
const rootUrl = 'https://houxu.app';
const currentUrl = `${rootUrl}/api/1/${id ? `lives/${id}/threads` : category === 'events' ? category : category === 'updated' || category === 'memory' ? 'lives/updated' : `records/${category}`}/?limit=${ctx.query.limit ?? 30}`;
const response = await got({
method: 'get',
url: currentUrl,
});
let items = response.data.results.map((item) => ({
guid: item.object?.id ?? item.id,
title: item.link?.title ?? item.object?.title ?? item.title,
link: item.link?.url ?? `${rootUrl}/lives/${item.object?.id ?? item.id}`,
pubDate: parseDate(item.create_at ?? item.object?.create_at ?? item.publish_at),
description: `<p>${item.link?.description ?? item.object?.summary ?? item.last?.link.description ?? item.description}</p>`,
author: item.link?.source ?? item.link?.media?.name ?? item.object?.creator?.username ?? item.object?.creator?.name ?? item.creator?.username ?? item.creator?.name ?? '',
}));
if (id) {
const detailResponse = await got({
method: 'get',
url: `${rootUrl}/api/1/lives/${id}`,
});
title = detailResponse.data.title;
description = detailResponse.data.summary;
author = detailResponse.data.creator.name;
} else {
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.guid, async () => {
try {
const detailResponse = await got({
method: 'get',
url: `${rootUrl}/api/1/lives/${item.guid}/threads/?limit=1000`,
});
const feeds = detailResponse.data.results.map((item) =>
art(path.join(__dirname, 'templates/description.art'), {
title: item.link.title,
link: item.link.url,
pubDate: parseDate(item.create_at),
description: `<p>${item.link.description}</p>`,
author: item.link.source ?? item.link.media?.name ?? '',
})
);
item.description = feeds.join('');
return item;
} catch (e) {
return Promise.resolve('');
}
})
)
);
}
ctx.state.data = {
title: `${title || categories[category]} - 后续`,
link: currentUrl,
item: items,
description,
author,
};
};

View File

@ -0,0 +1,4 @@
module.exports = {
'/lives/:id?': ['nczitzk'],
'/:category?': ['nczitzk'],
};

19
lib/v2/houxu/radar.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = {
'houxu.app': {
_name: '后续',
'.': [
{
title: '分类',
docs: 'https://docs.rsshub.app/new-media.html#hou-xu-fen-lei',
source: ['/:category', '/'],
target: '/houxu/:category?',
},
{
title: 'Lives',
docs: 'https://docs.rsshub.app/new-media.html#hou-xu-lives',
source: ['/lives/:id', '/'],
target: '/houxu/lives/:id',
},
],
},
};

3
lib/v2/houxu/router.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = function (router) {
router.get('/:category?/:id?', require('./index'));
};

View File

@ -0,0 +1,9 @@
<div>
<h3>
<a href="{{ link }}">{{ title }}</a>
</h3>
<p>{{ description }}</p>
<small><b>来源</b> {{ author }}</small>
<br>
<small><b>时间</b> {{ pubDate }}</small>
</div>