UNPKG

rsshub

Version:
101 lines (98 loc) 4.97 kB
import "./types-DNj6Etbg.mjs"; import { t as parseDate } from "./parse-date-Cr0wQjV_.mjs"; import { t as cache_default } from "./cache-BkqOokyU.mjs"; import { t as got_default } from "./got-BTowW50G.mjs"; import { load } from "cheerio"; //#region lib/routes/hackernews/index.ts const route = { path: "/:section?/:type?/:value?", categories: ["programming"], view: 0, example: "/hackernews/threads/comments_list/dang", parameters: { section: { description: "Content section, default to `index`. Common sections: `index`, `newest`, `ask`, `show`, `jobs`, `over`, `threads`, `submitted`. Any valid HN section (e.g. `best`, `front`, `active`) is also accepted" }, type: { description: "Content format, default to `sources`. `sources` links to original articles, `comments` fetches full comment threads, `comments_list` shows parent story with single comment" }, value: { description: "For `threads`/`submitted` sections, set user ID. For `over` section, set minimum points threshold (default 100). For other sections, appended as `?id=<value>` (e.g. `value=dang` → `?id=dang`)" } }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["news.ycombinator.com/:section", "news.ycombinator.com/"] }], name: "Stories", maintainers: ["nczitzk", "xie-dongping"], handler, description: `Subscribe to Hacker News content by section, user, or minimum points Examples: | HN100 | User submitted | User threads | Comments list | | ------------------ | ------------------------------------ | ---------------------------------- | ---------------------------------------- | | \`/hackernews/over\` | \`/hackernews/submitted/sources/dang\` | \`/hackernews/threads/sources/dang\` | \`/hackernews/threads/comments_list/dang\` |` }; async function handler(ctx) { const section = ctx.req.param("section") ?? "index"; const type = ctx.req.param("type") ?? "sources"; const value = ctx.req.param("value") ?? ""; const rootUrl = "https://news.ycombinator.com"; const sectionUrl = section === "index" ? "" : `/${section}`; let optUrl = value === "" ? "" : "?id=" + value; if (section === "over") optUrl = value === "" ? "?points=100" : "?points=" + value; const currentUrl = `${rootUrl}${sectionUrl}${optUrl}`; const $ = load((await got_default(currentUrl)).data); const list = $(".athing").slice(0, ctx.req.query("limit") ? Number.parseInt(ctx.req.query("limit")) : 30).toArray().map((thing) => { const $thing = $(thing); const item = { guid: $thing.attr("id"), title: $thing.find(".titleline").children("a").text(), category: $thing.find(".sitestr").text(), author: $thing.next().find(".hnuser").text(), pubDate: parseDate($thing.find(".age").attr("title") ?? $thing.next().find(".age").attr("title")), link: "", origin: $thing.find(".titleline").children("a").attr("href"), onStory: $thing.find(".onstory").text().slice(2), comments: $thing.next().find("a").last().text().split("\xA0comment", 1)[0], upvotes: $thing.next().find(".score").text().split(" point", 1)[0], currentComment: $thing.find(".comment").text(), description: "" }; item.link = `${rootUrl}/item?id=${item.guid}`; 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; }); const items = await Promise.all(list.map((item) => cache_default.tryGet(item.guid, async () => { if (item.comments !== "discuss" && type === "comments") { const content = load((await got_default({ method: "get", url: item.link })).data); content(".reply").remove(); item.description = ""; content(".comtr").each((_, el) => { const author = content(el).find(".hnuser"); const comment = content(el).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(el).attr("id")}">${content(el).find(".age").attr("title")}</a></small></div>`; const leading = content(`<p>${comment.contents().not("p").text()}</p>`); const paragraphs = comment.find("p").toArray().map((p) => `<p>${content(p).html()}</p>`).join(""); item.description += `<div>${content.html(leading)}${paragraphs}</div></div>`; }); } else if (item.comments !== "discuss" && type === "comments_list") { item.title = item.onStory; item.description = item.currentComment; } if (Number.isNaN(item.comments)) item.comments = 0; item.link = type === "sources" ? item.origin : item.link; delete item.origin; return item; }))); return { title: $("title").text(), link: currentUrl, item: items }; } //#endregion export { route };