mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-02 18:18:06 +08:00
fix(route): Hacker News (#8420)
This commit is contained in:
@@ -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 RSS:https://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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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'));
|
||||||
|
|||||||
@@ -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,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
97
lib/v2/hackernews/index.js
Normal file
97
lib/v2/hackernews/index.js
Normal 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>` +
|
||||||
|
`  <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,
|
||||||
|
};
|
||||||
|
};
|
||||||
3
lib/v2/hackernews/maintainer.js
Normal file
3
lib/v2/hackernews/maintainer.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
'/:section?/:type?': ['nczitzk'],
|
||||||
|
};
|
||||||
13
lib/v2/hackernews/radar.js
Normal file
13
lib/v2/hackernews/radar.js
Normal 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?',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
3
lib/v2/hackernews/router.js
Normal file
3
lib/v2/hackernews/router.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = function (router) {
|
||||||
|
router.get('/:section?/:type?', require('./index'));
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user