Replies: 2 comments 3 replies
-
|
https://docs.rsshub.app/guide/parameters#filtering Is this what you want? |
Beta Was this translation helpful? Give feedback.
3 replies
-
|
If you can accept rebuilding the project (this will take some time), you can create import { promisify } from 'util';
import zlib from 'zlib';
import RSSParser from 'rss-parser';
import type { Data, Route } from '@/types';
import got from '@/utils/got';
const gunzip = promisify(zlib.gunzip);
const inflate = promisify(zlib.inflate);
const brotliDecompress = promisify(zlib.brotliDecompress);
export const route: Route = {
path: '/proxy',
categories: ['other'],
example: '/custom/proxy?url=https://rsshub.app/sspai/index',
parameters: {
url: 'RSS feed URL to proxy',
},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'RSS Proxy',
maintainers: [],
handler,
description: 'RSS Proxy',
};
async function handler(ctx): Promise<Data> {
const url = ctx.req.query('url');
if (!url) {
throw new Error('URL parameter is required');
}
// 1. Instantiate a new Parser, configuring customFields to force capturing Atom's category tags
const parser = new RSSParser({
customFields: {
item: [
['category', 'categories', { keepArray: true }],
['content', 'content', { keepArray: false }],
['summary', 'summary', { keepArray: false }]
],
},
});
// 2. Initiate the request
const response = await got({
method: 'get',
url: url,
responseType: 'buffer',
headers: {
'Accept-Encoding': 'gzip, deflate, br',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 RSSHub/1.0',
},
});
// 3. Data fetching and defensive handling
let data: Buffer;
// @ts-ignore
const rawData = response.data || response.body || response;
if (Buffer.isBuffer(rawData)) {
data = rawData;
} else if (typeof rawData === 'string') {
data = Buffer.from(rawData);
} else {
data = Buffer.from('');
}
// 4. Safely read Headers
// @ts-ignore
const headers = response.headers || {};
const contentEncoding = (headers['content-encoding'] || '').toLowerCase();
// 5. Smart decompression
try {
if (data.length > 2 && data[0] === 0x1f && data[1] === 0x8b) {
data = await gunzip(data);
} else if (data.length > 2 && data[0] === 0x78) {
data = await inflate(data);
} else if (contentEncoding === 'br') {
data = await brotliDecompress(data);
}
} catch (e) {
console.error(`[Proxy] Decompression error for ${url}:`, e);
}
// 6. Parse XML
const contentString = data.toString('utf-8');
if (!contentString.trim()) {
throw new Error('Empty response body');
}
const feed = await parser.parseString(contentString);
// 7. Map data
const items = (feed.items || []).map((item: any) => {
const enclosure = item.enclosure;
let categories: string[] = [];
if (Array.isArray(item.categories)) {
categories = item.categories.map((c: any) => {
// Case 1: RSS standard <category>Text</category> -> Parsed as string "Text"
if (typeof c === 'string') return c;
// Case 2: Atom standard <category term="Text" /> -> Parsed as { $: { term: "Text" } }
if (c?.$?.term) return c.$.term;
// Fallback: Attempt to read name or label
if (c?.name) return c.name;
if (c?.label) return c.label;
if (c?._) return c._;
return null;
}).filter((c) => c && typeof c === 'string');
}
let authorName = '';
if (typeof item.creator === 'string') {
authorName = item.creator;
} else if (typeof item.author === 'string') {
authorName = item.author;
} else if (item.author && item.author.name) {
// Handle Atom's author structure
authorName = Array.isArray(item.author.name) ? item.author.name[0] : item.author.name;
}
return {
title: item.title ?? item.link ?? 'Untitled',
// Priority order: content -> summary (Atom) -> description (RSS)
description: item.content || item.summary || item.description || '',
link: item.link,
pubDate: item.isoDate ?? item.pubDate,
author: authorName,
category: categories,
guid: item.guid || item.id || item.link,
...(enclosure?.url && {
enclosure_url: enclosure.url,
enclosure_type: enclosure.type,
enclosure_length: enclosure.length ? Number(enclosure.length) : undefined,
}),
};
});
return {
title: feed.title ?? 'RSS Proxy Feed',
description: feed.description ?? '',
link: feed.link ?? url,
image: feed.image?.url,
language: feed.language,
item: items,
...(feed.itunes?.author && { itunes_author: feed.itunes.author }),
...(feed.itunes?.categories?.[0] && { itunes_category: feed.itunes.categories[0] }),
};
}Then you can use the The RSSHub project mentions No Custom Query Parameters, so I assume this feature might not be added. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
hello, this may be a silly question, but is there currently a way to filter an existing rss feed? chatgpt mentions an existing_feed route but I'm not seeing any info for it, eg:
https://rsshub.app/existing_feed?url=your_rss_feed_url&filter=keyword1|keyword2
thanks
Beta Was this translation helpful? Give feedback.
All reactions