UNPKG

@dendaio/n8n-nodes-collection

Version:

🚀 Comprehensive n8n node collection for financial analysis and automation. Features 55+ technical indicators (RSI, MACD, Bollinger Bands), 32+ candlestick patterns (Doji, Hammer, Engulfing), automated trading strategies, RSS feed processing, and OAuth2 v

355 lines • 17.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MultiRssFeedRead = void 0; const n8n_workflow_1 = require("n8n-workflow"); const rss_parser_1 = __importDefault(require("rss-parser")); const axios_1 = __importDefault(require("axios")); function validateURL(url) { try { const urlPattern = new RegExp('^(https?:\\/\\/)?' + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + '((\\d{1,3}\\.){3}\\d{1,3}))' + '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + '(\\?[;&a-z\\d%_.~+=-]*)?' + '(\\#[-a-z\\d_]*)?$', 'i'); return urlPattern.test(url); } catch (err) { return false; } } class MultiRssFeedRead { constructor() { this.description = { displayName: 'Multi RSS Read', name: 'multiRssFeedRead', icon: 'fa:rss', iconColor: 'orange-red', group: ['input'], version: [1], description: 'Reads data from multiple RSS Feeds in parallel', defaults: { name: 'Multi RSS Read', color: '#b02020', }, usableAsTool: true, inputs: ["main"], outputs: ["main", "main"], outputNames: ['Success', 'Error'], properties: [ { displayName: 'URLs', name: 'urls', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: {}, placeholder: 'Add RSS URL', options: [ { name: 'urlValues', displayName: 'URL', values: [ { displayName: 'URL', name: 'url', type: 'string', default: '', required: true, description: 'URL of the RSS feed', placeholder: 'https://example.com/rss', }, ], }, ], }, { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add option', default: {}, options: [ { displayName: 'Continue On Error', name: 'continueOnError', type: 'boolean', default: true, description: 'Whether to continue processing other feeds if one fails', }, { displayName: 'Custom Fields', name: 'customFields', type: 'string', default: '', description: 'A comma-separated list of custom fields to include in the output. For example, "author, contentSnippet".', }, { displayName: 'Custom Headers', name: 'customHeaders', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: {}, placeholder: 'Add custom header', description: 'Add custom HTTP headers to the request', options: [ { name: 'headerValues', displayName: 'Header', values: [ { displayName: 'Header Name', name: 'name', type: 'string', default: '', required: true, description: 'Name of the HTTP header', placeholder: 'X-Custom-Header', }, { displayName: 'Header Value', name: 'value', type: 'string', default: '', required: true, description: 'Value of the HTTP header', placeholder: 'custom-value', }, ], }, ], }, { displayName: 'Ignore SSL Issues (Insecure)', name: 'ignoreSSL', type: 'boolean', default: false, description: 'Whether to ignore SSL/TLS certificate issues or not', }, { displayName: 'Include Source URL', name: 'includeSourceUrl', type: 'boolean', default: true, description: 'Whether to include the source URL in each item', }, { displayName: 'User Agents', name: 'userAgents', type: 'fixedCollection', typeOptions: { multipleValues: true, }, default: {}, placeholder: 'Add user agent', description: 'Add multiple User-Agent strings (one will be randomly selected for each request)', options: [ { name: 'userAgentValues', displayName: 'User Agent', values: [ { displayName: 'User Agent String', name: 'userAgent', type: 'string', default: '', required: true, description: 'User-Agent string to use', placeholder: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...', }, ], }, ], }, ], }, ], }; } async execute() { var _a, _b; const successData = []; const errorData = []; const items = this.getInputData(); for (let i = 0; i < items.length; i++) { try { const urlsData = this.getNodeParameter('urls', i); const options = this.getNodeParameter('options', i); const ignoreSSL = Boolean(options.ignoreSSL); const continueOnError = Boolean((_a = options.continueOnError) !== null && _a !== void 0 ? _a : true); const includeSourceUrl = Boolean((_b = options.includeSourceUrl) !== null && _b !== void 0 ? _b : true); const urlValues = urlsData.urlValues || []; const urls = urlValues.map((item) => item.url).filter(Boolean); if (urls.length === 0) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'At least one URL must be provided!', { itemIndex: i, }); } const invalidUrls = urls.filter((url) => !validateURL(url)); if (invalidUrls.length > 0) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `The following URLs are not valid: ${invalidUrls.join(', ')}`, { itemIndex: i, }); } const parserOptions = {}; if (options.customFields) { const customFields = options.customFields; parserOptions.customFields = { item: customFields.split(',').map((field) => field.trim()), }; } const fetchRssWithAxios = async (url) => { try { const userAgentsData = options.userAgents; let availableUserAgents = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', ]; if (userAgentsData && userAgentsData.userAgentValues) { const userAgentValues = userAgentsData.userAgentValues; const customUserAgents = userAgentValues .map((ua) => ua.userAgent) .filter(Boolean); if (customUserAgents.length > 0) { availableUserAgents = customUserAgents; } } const selectedUserAgent = availableUserAgents[Math.floor(Math.random() * availableUserAgents.length)]; const headers = { Accept: 'application/rss+xml, application/rdf+xml;q=0.8, application/atom+xml;q=0.6, application/xml;q=0.4, text/xml;q=0.4, */*;q=0.1', 'User-Agent': selectedUserAgent, 'Accept-Language': 'en-US,en;q=0.9', 'Accept-Encoding': 'gzip, deflate, br', 'Cache-Control': 'no-cache', Pragma: 'no-cache', DNT: '1', 'Upgrade-Insecure-Requests': '1', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'none', 'Sec-Fetch-User': '?1', }; const customHeadersData = options.customHeaders; if (customHeadersData && customHeadersData.headerValues) { const headerValues = customHeadersData.headerValues; for (const header of headerValues) { if (header.name && header.value) { headers[header.name] = header.value; } } } const axiosConfig = { timeout: 30000, headers, httpsAgent: ignoreSSL ? new (require('https').Agent)({ rejectUnauthorized: false }) : undefined, }; const response = await axios_1.default.get(url, axiosConfig); if (response.status !== 200) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `HTTP ${response.status}: ${response.statusText}`, { itemIndex: i }); } const parser = new rss_parser_1.default(parserOptions); const feed = await parser.parseString(response.data); if (feed.items) { const feedItems = feed.items.map((item) => { const json = { ...item }; if (includeSourceUrl) { json.sourceUrl = url; } return { json }; }); return { url, items: feedItems, }; } return { url, items: [], }; } catch (error) { if (continueOnError) { let errorMessage = error instanceof Error ? error.message : String(error); if (errorMessage.includes('Status code 403')) { errorMessage = 'Access forbidden (403) - This site may be blocking automated requests. Try adding custom headers or contact the site administrator.'; } else if (errorMessage.includes('Status code 429')) { errorMessage = 'Too many requests (429) - Rate limit exceeded. Try again later.'; } else if (errorMessage.includes('Status code 404')) { errorMessage = 'RSS feed not found (404) - The URL may be incorrect or the feed may have been moved.'; } else if (errorMessage.includes('ENOTFOUND')) { errorMessage = 'Domain not found - Check if the URL is correct and the domain exists.'; } else if (errorMessage.includes('ECONNREFUSED')) { errorMessage = 'Connection refused - The server may be down or blocking connections.'; } else if (errorMessage.includes('ETIMEDOUT')) { errorMessage = 'Connection timeout - The server took too long to respond.'; } else if (errorMessage.includes('Network Error')) { errorMessage = 'Network error - Check your internet connection and try again.'; } return { url, items: [], error: errorMessage, }; } throw error; } }; const results = await Promise.all(urls.map(fetchRssWithAxios)); for (const result of results) { if (result.error && !continueOnError) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to fetch RSS feed from ${result.url}: ${result.error}`, { itemIndex: i, }); } if (result.error) { errorData.push({ json: { error: result.error, sourceUrl: result.url, message: `Failed to fetch RSS feed from ${result.url}`, }, pairedItem: [{ item: i }], }); } else { const itemData = [{ item: i }]; const executionData = this.helpers.constructExecutionMetaData(result.items, { itemData, }); successData.push(...executionData); } } } catch (error) { if (this.continueOnFail()) { errorData.push({ json: { error: error instanceof Error ? error.message : String(error) }, pairedItem: [{ item: i }], }); continue; } throw error; } } return [successData, errorData]; } } exports.MultiRssFeedRead = MultiRssFeedRead; //# sourceMappingURL=MultiRssFeedRead.node.js.map