rsshub
Version:
Make RSS Great Again!
117 lines (114 loc) • 6.04 kB
JavaScript
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 };