2026-06-14 22:48:52 +08:00

60 lines
2.5 KiB
JavaScript

import getServiceWidget from "utils/config/service-helpers";
import createLogger from "utils/logger";
const logger = createLogger("freshrsslist");
export default async function freshrsslistProxyHandler(req, res) {
try {
const { group, service } = req.query;
const serviceWidget = await getServiceWidget(group, service);
if (!serviceWidget) {
return res.status(400).json({ error: "Widget not found" });
}
const { url, username, password, category, limit } = serviceWidget;
const itemLimit = parseInt(limit, 10) || 5;
if (!url || !username || !password) {
return res.status(400).json({ error: "Missing required fields" });
}
const baseUrl = url.replace(/\/+$/, "");
// 1) ClientLogin to get Auth token
const loginUrl = `${baseUrl}/api/greader.php/accounts/ClientLogin`;
const loginRes = await fetch(loginUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `Email=${encodeURIComponent(username)}&Passwd=${encodeURIComponent(password)}`,
});
const loginText = await loginRes.text();
const authMatch = loginText.match(/Auth=([^\n]+)/);
if (!authMatch) {
logger.error(`FreshRSS ClientLogin failed: ${loginText}`);
return res.status(401).json({ error: "FreshRSS auth failed" });
}
const authToken = authMatch[1];
// 2) Fetch reading list with GoogleLogin auth header
const streamPath = category
? `user/-/label/${encodeURIComponent(category)}`
: "user/-/state/com.google/reading-list";
const targetUrl = `${baseUrl}/api/greader.php/reader/api/0/stream/contents/${streamPath}?n=${itemLimit}&output=json&r=n`;
const response = await fetch(targetUrl, {
headers: { Authorization: `GoogleLogin auth=${authToken}` },
});
if (!response.ok) {
logger.error(`FreshRSS returned ${response.status}`);
return res
.status(response.status)
.json({ error: `HTTP ${response.status}` });
}
const json = await response.json();
const items = (json.items || []).map((item) => ({
id: item.id || item.timestampUsec,
title: item.title || "Untitled",
url: item.alternate?.[0]?.href || item.canonical?.[0]?.href || "",
author: item.author || "",
created_on_time: item.published || Math.floor(Date.now() / 1000),
feed_name: item.origin?.title || "",
}));
return res.status(200).json({ items });
} catch (err) {
logger.error(err);
return res.status(500).json({ error: err.message });
}
}