rsshub
Version:
Make RSS Great Again!
183 lines (181 loc) • 6.74 kB
JavaScript
import "./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 "./helpers-DxBp0Pty.mjs";
import { t as got_default } from "./got-KxxWdaxq.mjs";
import { t as rss_parser_default } from "./rss-parser-Dtop7M8f.mjs";
import dayjs from "dayjs";
import { load } from "cheerio";
import timezone from "dayjs/plugin/timezone.js";
import utc from "dayjs/plugin/utc.js";
//#region lib/routes/phoronix/index.ts
dayjs.extend(utc);
dayjs.extend(timezone);
const redirectCacheKey = "phoronix:redirect";
const webArticlesCacheKey = "phoronix:web-articles";
const articleCacheKey = "phoronix:articles";
const baseUrl = "https://www.phoronix.com";
const rssUrl = `${baseUrl}/rss.php`;
const feedFetch = async () => {
const feedStr = await ofetch_default(rssUrl);
const feed = await rss_parser_default.parseString(feedStr);
return {
title: feed.title,
link: feed.link,
description: feed.description,
item: feed.items,
language: feed.language,
icon: "https://www.phoronix.com/android-chrome-192x192.png",
image: "https://www.phoronix.com/android-chrome-192x192.png",
logo: "https://www.phoronix.com/phxcms7-css/phoronix.png",
category: [
"Linux Hardware Reviews",
"Linux hardware benchmarks",
"Linux Hardware",
"Linux benchmarking",
"Desktop Linux",
"GNU/Linux benchmarks",
"Open Source AMD",
"Linux How To",
"X.Org drivers",
"Ubuntu hardware",
"Phoronix Test Suite"
]
};
};
const webFetchCb = (response) => {
const $ = load(response.body);
return {
title: $("title").text(),
link: response.url,
description: $("meta[name=\"Description\"]").attr("content"),
item: [...new Set($("#main a").toArray().map((e) => e.attribs.href))].filter((link) => link && (link.startsWith("/review/") || link.startsWith("/news/"))).map((link) => ({ link: `${baseUrl}${link}` })),
language: "en-us",
icon: "https://www.phoronix.com/android-chrome-192x192.png",
image: "https://www.phoronix.com/android-chrome-192x192.png",
logo: "https://www.phoronix.com/phxcms7-css/phoronix.png",
category: $("meta[name=\"keywords\"]").attr("content").split(", ")
};
};
const webFetch = (url) => cache_default.tryGet(`${webArticlesCacheKey}:${url}`, async () => {
try {
return webFetchCb(await got_default(url));
} catch (error) {
if ((error.name === "HTTPError" || error.name === "FetchError") && error.response.statusCode === 404) return "404";
throw error;
}
});
const legacyFetch = async (page, queryOrItem) => {
const legacyUrl = new URL("/scan.php", baseUrl);
legacyUrl.searchParams.set("page", page);
if (queryOrItem) if (page === "category") legacyUrl.searchParams.set("item", queryOrItem);
else legacyUrl.searchParams.set("q", queryOrItem);
let response;
const webUrl = await cache_default.tryGet(`${redirectCacheKey}:${legacyUrl.toString()}`, async () => {
response = await got_default(legacyUrl.toString());
return response.url;
});
if (response) {
const feed = webFetchCb(response);
cache_default.set(`${webArticlesCacheKey}:${webUrl}`, feed);
return feed;
}
return await webFetch(webUrl);
};
const tryFetch = async (category, topic) => {
let feed = await webFetch(topic ? `${baseUrl}/${category}/${topic}` : `${baseUrl}/${category}`);
if (feed === "404") feed = await legacyFetch(category, topic);
return feed;
};
const route = {
path: "/:category?/:topic?",
categories: ["new-media"],
example: "/phoronix/linux/KDE",
parameters: {
category: "Category",
topic: "Topic. You may find available parameters from their navigator links. E.g. to subscribe to `https://www.phoronix.com/reviews/Operating+Systems`, fill in the path `/phoronix/reviews/Operating+Systems`"
},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false
},
radar: [{ source: ["phoronix.com/:category?/:topic?"] }],
name: "News & Reviews",
maintainers: ["oppliate", "Rongronggg9"],
handler
};
async function handler(ctx) {
const { category, topic } = ctx.req.param();
let feed;
switch (category) {
case "category":
case "news_topic":
feed = await legacyFetch(category, topic);
break;
case "rss":
feed = await feedFetch();
break;
default:
feed = category ? await tryFetch(category, topic) : await feedFetch();
break;
}
feed.item = await Promise.all(feed.item.map((item) => cache_default.tryGet(`${articleCacheKey}:${item.link}`, async () => {
const html = (await got_default(item.link)).body;
const $ = load(html);
const content = $(".content");
const authorSelector = $(".author > a");
const author = authorSelector.slice(0, -2).toArray().map((e) => $(e).text());
const category$1 = [];
if (item.link.includes("/news/")) category$1.push("News");
else if (item.link.includes("/review/")) category$1.push("Review");
const categorySelector = authorSelector.eq(-2);
if (categorySelector.length) category$1.push(categorySelector.text());
let pubDate;
if (!item.pubDate) {
let pubDateReadable = categorySelector.length && categorySelector[0].nextSibling?.nodeValue;
if (pubDateReadable) {
pubDateReadable = pubDateReadable.replaceAll(/on|at|\./g, "").trim();
pubDate = /\d{4}$/.test(pubDateReadable) ? dayjs.utc(`${pubDateReadable} 08:00 UTC`).tz("America/Indiana/Indianapolis", true) : dayjs(pubDateReadable);
if (!pubDate.isValid()) pubDate = pubDateReadable;
}
}
const links = $(".pagination > a").toArray().map((pager) => `${baseUrl}${pager.attribs.href}`).slice(0, -1);
if (links.length) {
const pages = await Promise.all(links.map((link) => cache_default.tryGet(link, async () => {
const html$1 = (await got_default(link)).data;
return load(html$1)(".content").html();
})));
content.append(pages);
}
const images = content.find("img");
const topicImage = images.first();
if (topicImage.attr("src")?.startsWith("/assets/categories/")) {
const topicImageContainer = topicImage.parent();
if (topicImageContainer.text().trim()) topicImage.remove();
else topicImageContainer.remove();
}
images.each((_, img) => {
img.attribs.src = img.attribs.src.replace(/_med$/, "");
});
return {
title: item.title || $("article h1").text(),
pubDate: item.pubDate || pubDate,
author: author.join(", "),
link: item.link,
summary: $("meta[name=\"twitter:description\"]").attr("content"),
description: content.html(),
image: $("meta[name=\"twitter:image\"]").attr("content"),
category: item.category || category$1
};
})));
return feed;
}
//#endregion
export { route };