mirror of
https://github.com/gethomepage/homepage.git
synced 2026-09-27 06:21:18 -07:00
62 lines
2.0 KiB
JavaScript
62 lines
2.0 KiB
JavaScript
import cache from "memory-cache";
|
|
|
|
import { parseFeed } from "./utils";
|
|
|
|
import getServiceWidget from "utils/config/service-helpers";
|
|
import createLogger from "utils/logger";
|
|
import { sanitizeErrorURL } from "utils/proxy/api-helpers";
|
|
import { httpProxy } from "utils/proxy/http";
|
|
|
|
const logger = createLogger("feedProxyHandler");
|
|
const CACHE_MS = 10 * 60 * 1000;
|
|
|
|
export default async function feedProxyHandler(req, res) {
|
|
const { group, service, index } = req.query;
|
|
const widget = await getServiceWidget(group, service, index);
|
|
|
|
if (!widget?.url) {
|
|
return res.status(400).json({ error: "Missing feed URL" });
|
|
}
|
|
|
|
let url;
|
|
try {
|
|
url = new URL(widget.url);
|
|
} catch {
|
|
return res.status(400).json({ error: "Invalid feed URL" });
|
|
}
|
|
|
|
const cacheKey = `feed:${url.href}`;
|
|
let items = cache.get(cacheKey);
|
|
|
|
if (!items) {
|
|
const [status, , data] = await httpProxy(url, {
|
|
headers: {
|
|
"User-Agent": `gethomepage/${process.env.NEXT_PUBLIC_VERSION || "dev"}`,
|
|
Accept: "application/rss+xml, application/atom+xml, application/xml;q=0.9, text/xml;q=0.9, */*;q=0.8",
|
|
},
|
|
});
|
|
|
|
if (status !== 200) {
|
|
logger.debug("HTTP %d retrieving feed %s//%s%s", status, url.protocol, url.host, url.pathname);
|
|
return res.status(status).json({ error: { message: "HTTP Error", url: sanitizeErrorURL(url) } });
|
|
}
|
|
|
|
try {
|
|
items = parseFeed(Buffer.from(data).toString(), url.href);
|
|
} catch (e) {
|
|
logger.debug("Error parsing feed %s//%s%s: %s", url.protocol, url.host, url.pathname, e.message);
|
|
return res.status(500).json({ error: { message: "Invalid feed", url: sanitizeErrorURL(url) } });
|
|
}
|
|
|
|
// only successful fetches are cached
|
|
cache.put(cacheKey, items, CACHE_MS);
|
|
}
|
|
|
|
const maxItems = parseInt(widget.maxItems, 10) || 5;
|
|
const showImages = widget.images !== false && widget.images !== "false";
|
|
|
|
return res.status(200).json({
|
|
items: items.slice(0, maxItems).map(({ image, ...item }) => (showImages && image ? { ...item, image } : item)),
|
|
});
|
|
}
|