UNPKG

rsshub

Version:
117 lines (114 loc) • 6.04 kB
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs"; import "./config-C37vj7VH.mjs"; import "./dist-BInvbO1W.mjs"; import "./logger-Czu8UMNd.mjs"; import { t as ofetch_default } from "./ofetch-BIyrKU3Y.mjs"; import { t as cache_default } from "./cache-Bo__VnGm.mjs"; import { t as art } from "./render-BQo6B4tL.mjs"; import { t as rss_parser_default } from "./rss-parser-Dtop7M8f.mjs"; import path from "node:path"; import { load } from "cheerio"; //#region lib/routes/theverge/index.ts init_esm_shims(); const excludeTypes = new Set([ "NewsletterBlockType", "RelatedPostsBlockType", "ProductsTableBlockType", "TableOfContentsBlockType" ]); const shouldKeep = (b) => !excludeTypes.has(b.__typename.trim()); const route = { path: "/:hub?", categories: ["new-media"], example: "/theverge", parameters: { hub: "Hub, see below, All Posts by default" }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["theverge.com/:hub", "theverge.com/"] }], name: "Category", maintainers: ["HenryQW", "vbali"], handler, description: `| Hub | Hub name | | ----------- | ------------------- | | | All Posts | | android | Android | | apple | Apple | | apps | Apps & Software | | blackberry | BlackBerry | | culture | Culture | | gaming | Gaming | | hd | HD & Home | | microsoft | Microsoft | | photography | Photography & Video | | policy | Policy & Law | | web | Web & Social | Provides a better reading experience (full text articles) over the official one.` }; const renderBlock = (b) => { if (!shouldKeep(b)) return ""; switch (b.__typename) { case "CoreEmbedBlockType": return b.embedHtml; case "CoreGalleryBlockType": return b.images.map((i) => `<figure><img src="${i.image.thumbnails.horizontal.url.split("?")[0]}" alt="${i.alt}" /><figcaption>${i.caption.html}</figcaption></figure>`).join(""); case "CoreHeadingBlockType": return `<h${b.level}>${b.contents.html}</h${b.level}>`; case "CoreHTMLBlockType": return b.markup; case "CoreImageBlockType": return `<figure><img src="${b.thumbnail.url.split("?")[0]}" alt="${b.alt}" /><figcaption>${b.caption.html}</figcaption></figure>`; case "CoreListBlockType": return `${b.ordered ? "<ol>" : "<ul>"}${b.items.map((i) => `<li>${i.contents.html}</li>`).join("")}${b.ordered ? "</ol>" : "</ul>"}`; case "CoreParagraphBlockType": return b.tempContents.map((c) => c.html).join(""); case "CorePullquoteBlockType": return `<blockquote>${b.contents.html}</blockquote>`; case "CoreQuoteBlockType": return `<blockquote>${b.children.map((child) => renderBlock(child)).join("")}</blockquote>`; case "CoreSeparatorBlockType": return "<hr>"; case "HighlightBlockType": return b.children.map((c) => renderBlock(c)).join(""); case "ImageCompareBlockType": return `<figure><img src="${b.leftImage.thumbnails.horizontal.url.split("?")[0]}" alt="${b.leftImage.alt}" /><img src="${b.rightImage.thumbnails.horizontal.url.split("?")[0]}" alt="${b.rightImage.alt}" /><figcaption>${b.caption.html}</figcaption></figure>`; case "ImageSliderBlockType": return b.images.map((i) => `<figure><img src="${i.image.originalUrl.split("?")[0]}" alt="${i.alt}" /><figcaption>${i.caption.html}</figcaption></figure>`).join(""); case "MethodologyAccordionBlockType": return `<h2>${b.heading.html}</h2>${b.sections.map((s) => `<h3>${s.heading.html}</h3>${s.content.html}`).join("")}`; case "ProductBlockType": { const product = b.product; return `<div><figure><img src="${product.image.thumbnails.horizontal.url.split("?")[0]}" alt="${product.image.alt}" /><figcaption>${product.image.alt}</figcaption></figure><br><a href="${product.bestRetailLink.url}">${product.title} $${product.bestRetailLink.price}</a><br>${product.description.html}${product.pros.html ? `<br>The Good${product.pros.html}The Bad${product.cons.html}` : ""}</div>`; } case "TableBlockType": return `<table><tr>${b.header.map((cell) => `<th>${cell}</th>`).join("")}</tr>${b.rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("")}</table>`; default: throw new Error(`Unsupported block type: ${b.__typename}`); } }; async function handler(ctx) { const link = ctx.req.param("hub") ? `https://www.theverge.com/rss/${ctx.req.param("hub")}/index.xml` : "https://www.theverge.com/rss/index.xml"; const feed = await rss_parser_default.parseURL(link); const items = await Promise.all(feed.items.map((item) => cache_default.tryGet(item.link, async () => { const $ = load(await ofetch_default(item.link)); const node = JSON.parse($("script#__NEXT_DATA__").text()).props.pageProps.hydration.responses.find((x) => x.operationName === "PostLayoutQuery" || x.operationName === "StreamLayoutQuery").data.node; let description = art(path.join(__dirname, "templates/header-f05d88a8.art"), { featuredImage: node.featuredImage, ledeMediaData: node.ledeMediaData }); description += node.blocks.map((b) => renderBlock(b)).join("<br><br>"); if (node.__typename === "StreamResourceType") description += node.posts.edges.map(({ node: n }) => { let d = `<h2><a href="${n.permalink}">${n.promo.headline || n.title}</a></h2>` + art(path.join(__dirname, "templates/header-f05d88a8.art"), { ledeMediaData: n.ledeMediaData }); switch (n.__typename) { case "PostResourceType": d += n.excerpt.map((e) => e.contents.html).join("<br>"); break; case "QuickPostResourceType": d += n.blocks.map((b) => renderBlock(b)).join("<br>"); break; default: break; } return d; }).join("<br>"); item.description = description; item.category = node.categories; return item; }))); return { title: feed.title, link: feed.link, description: feed.description, item: items }; } //#endregion export { route };