fix(route): Hacker News (#8420)

This commit is contained in:
Ethan Shen
2022-01-22 23:56:47 +08:00
committed by GitHub
parent f944cc9a69
commit bd500ce58b
8 changed files with 140 additions and 94 deletions

View File

@@ -137,26 +137,21 @@ For instance, the `/github/topics/framework/l=php&o=desc&s=stars` route will gen
### Section ### Section
<RouteEn author="cf020031308" example="/hackernews/best/comments" path="/hackernews/:section/:type?" :paramsDesc="['Section', 'Link type']"> <RouteEn author="cf020031308 nczitzk" example="/hackernews" path="/hackernews/:section?/:type?" :paramsDesc="['Section, see below, index by default', 'Link, see below, sources by default']">
Website: https://news.ycombinator.com/ Section
| Section | section | | homepage | new | past | comments | ask | show | jobs | best |
| ------- | ----------------------------------- | | ------------------------------------- | --------------------------------------------- | ------------------------------------------- | ------------------------------------------------------- | --------------------------------------- | ----------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| index | https://news.ycombinator.com/ | | [index](https://news.ycombinator.com) | [newest](https://news.ycombinator.com/newest) | [front](https://news.ycombinator.com/front) | [newcomments](https://news.ycombinator.com/newcomments) | [ask](https://news.ycombinator.com/ask) | [show](https://news.ycombinator.com/show) | [jobs](https://news.ycombinator.com/jobs) | [best](https://news.ycombinator.com/best) |
| new | https://news.ycombinator.com/newest |
| past | https://news.ycombinator.com/front |
| ask | https://news.ycombinator.com/ask |
| show | https://news.ycombinator.com/show |
| jobs | https://news.ycombinator.com/jobs |
| best | https://news.ycombinator.com/best |
> Official RSShttps://news.ycombinator.com/rss is same as `index` section Items link to
| Link type | type | | Source addresses shared by users | Comments on Hacker News |
| --------- | ------------------------------ | | -------------------------------- | ----------------------- |
| story | Deault, link to shared address | | sources | comments |
| comments | Link to Hacker News address |
> Default RSS by the website: <https://news.ycombinator.com/rss>, same as `index` section, should be the first choice.
</RouteEn> </RouteEn>

View File

@@ -219,28 +219,23 @@ GitHub 官方也提供了一些 RSS:
## Hacker News ## Hacker News
### 分 ### 分
<Route author="cf020031308" example="/hackernews/best/comments" path="/hackernews/:section/:type?" :paramsDesc="['内容分区', '链接类型(可不填)']"> <Route author="cf020031308 nczitzk" example="/hackernews" path="/hackernews/:section?/:type?" :paramsDesc="['内容分区,见下表,默认为 index', '链接类型,见下表,默认为 sources']">
网站地址:<https://news.ycombinator.com/> 内容分区
| 内容分区 | section | | homepage | new | past | comments | ask | show | jobs | best |
| -------- | ------------------------------------- | | ------------------------------------- | --------------------------------------------- | ------------------------------------------- | ------------------------------------------------------- | --------------------------------------- | ----------------------------------------- | ----------------------------------------- | ----------------------------------------- |
| index | <https://news.ycombinator.com/> | | [index](https://news.ycombinator.com) | [newest](https://news.ycombinator.com/newest) | [front](https://news.ycombinator.com/front) | [newcomments](https://news.ycombinator.com/newcomments) | [ask](https://news.ycombinator.com/ask) | [show](https://news.ycombinator.com/show) | [jobs](https://news.ycombinator.com/jobs) | [best](https://news.ycombinator.com/best) |
| new | <https://news.ycombinator.com/newest> |
| past | <https://news.ycombinator.com/front> |
| ask | <https://news.ycombinator.com/ask> |
| show | <https://news.ycombinator.com/show> |
| jobs | <https://news.ycombinator.com/jobs> |
| best | <https://news.ycombinator.com/best> |
> 网站有默认的 RSS<https://news.ycombinator.com/rss> 内容同 index应优先考虑 条目指向链接类型
| 链接类型 | type | | 用户分享的来源地址 | Hacker News 上的讨论页面 |
| -------- | ----------------------------- | | ------------------ | ------------------------ |
| story | 默认值,链向用户分享的地址 | | sources | comments |
| comments | 链向 Hacker News 上的讨论页面 |
> 网站有默认的 RSS<https://news.ycombinator.com/rss> 内容同 homepage应优先考虑。
</Route> </Route>

View File

@@ -1434,7 +1434,7 @@ router.get('/aisixiang/ranking/:type?/:range?', lazyloadRouteHandler('./routes/a
router.get('/aisixiang/thinktank/:name/:type?', lazyloadRouteHandler('./routes/aisixiang/thinktank')); router.get('/aisixiang/thinktank/:name/:type?', lazyloadRouteHandler('./routes/aisixiang/thinktank'));
// Hacker News // Hacker News
router.get('/hackernews/:section/:type?', lazyloadRouteHandler('./routes/hackernews/story')); // router.get('/hackernews/:section/:type?', lazyloadRouteHandler('./routes/hackernews/story'));
// LeetCode // LeetCode
router.get('/leetcode/articles', lazyloadRouteHandler('./routes/leetcode/articles')); router.get('/leetcode/articles', lazyloadRouteHandler('./routes/leetcode/articles'));

View File

@@ -1,60 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const host = 'https://news.ycombinator.com';
const paths = {
index: '/',
new: '/newest',
past: '/front',
ask: '/ask',
show: '/show',
jobs: '/jobs',
best: '/best',
};
module.exports = async (ctx) => {
const section = ctx.params.section;
const showStory = ctx.params.type !== 'comments';
const path = paths[section];
const url = `${host}${path}`;
const response = await got.get(url);
const $ = cheerio.load(response.data);
const items = $('a.storylink')
.map(function () {
return {
title: $(this).text(),
link: $(this).attr('href'),
author: 'Hacker News',
description: '',
};
})
.get();
$('a.hnuser').each(function (i) {
items[i].author = $(this).text();
});
$('tr.athing').each(function (i) {
const commURL = `${host}/item?id=` + $(this).attr('id');
const item = items[i];
if (showStory) {
item.description = `Comments: <a href="${commURL}"> ${commURL} </a>`;
} else {
item.description = `Link: <a href="${item.link}"> ${item.title} </a>`;
item.link = commURL;
}
});
let title = `Hacker News: ${section}`;
if (!showStory) {
title += '/comments';
}
ctx.state.data = {
title,
link: url,
item: items,
};
};

View File

@@ -0,0 +1,97 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
module.exports = async (ctx) => {
const section = ctx.params.section ?? 'index';
const type = ctx.params.type ?? 'sources';
const rootUrl = 'https://news.ycombinator.com';
const currentUrl = `${rootUrl}${section === 'index' ? '' : `/${section}`}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const $ = cheerio.load(response.data);
const list = $('.athing')
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 30)
.map((_, thing) => {
thing = $(thing);
const item = {};
item.guid = thing.attr('id');
item.title = thing.find('.titlelink').text();
item.category = thing.find('.sitestr').text();
item.author = thing.next().find('.hnuser').text();
item.pubDate = parseDate(thing.next().attr('title'));
item.link = `${rootUrl}/item?id=${item.guid}`;
item.origin = thing.find('.titlelink').attr('href');
item.comments = thing.next().find('a').last().text().split(' comment')[0];
item.guid = type === 'sources' ? item.guid : `${item.guid}${item.comments === 'discuss' ? '' : `-${item.comments}`}`;
item.description = `<a href="${item.link}">Comments on Hacker News</a> | <a href="${item.origin}">Source</a>`;
return item;
})
.get();
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.guid, async () => {
if (item.comments !== 'discuss' && type !== 'sources') {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
content('.reply').remove();
item.description = '';
content('.comtr').each(function () {
const author = content(this).find('.hnuser');
const comment = content(this).find('.commtext');
item.description +=
`<div><div><small><a href="${rootUrl}/${author.attr('href')}">${author.text()}</a></small>` +
`&nbsp&nbsp<small><a href="${rootUrl}/item?id=${content(this).attr('id')}">` +
`${content(this).find('.age').attr('title')}</a></small></div>`;
const commentText = comment.clone();
commentText.find('p').remove();
commentText.html(`<p>${commentText.text()}</p>`);
commentText.append(
comment
.find('p')
.toArray()
.map((p) => `<p>${content(p).html()}</p>`)
);
item.description += `<div>${commentText.html()}</div></div>`;
});
}
item.link = type === 'sources' ? item.origin : item.link;
delete item.origin;
return item;
})
)
);
ctx.state.data = {
title: $('title').text(),
link: currentUrl,
item: items,
};
};

View File

@@ -0,0 +1,3 @@
module.exports = {
'/:section?/:type?': ['nczitzk'],
};

View File

@@ -0,0 +1,13 @@
module.exports = {
'ycombinator.com': {
_name: 'Hacker News',
'.': [
{
title: 'Section',
docs: 'https://docs.rsshub.app/programming.html#hacker-news',
source: ['/:section', '/'],
target: '/hackernews/:section?/:type?',
},
],
},
};

View File

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