n8n-nodes-duckduckgo-search
Version:
A powerful and comprehensive n8n community node that seamlessly integrates DuckDuckGo search capabilities into your workflows. Search the web, find images, discover news, and explore videos - all with privacy-focused, reliable results.
421 lines (420 loc) • 15.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSearchOperators = exports.parseSearchOperators = exports.buildSearchQuery = exports.OPERATOR_INFO = exports.SearchOperator = void 0;
var SearchOperator;
(function (SearchOperator) {
SearchOperator["Site"] = "site:";
SearchOperator["Filetype"] = "filetype:";
SearchOperator["Intitle"] = "intitle:";
SearchOperator["Inurl"] = "inurl:";
SearchOperator["InBody"] = "inbody:";
SearchOperator["Cache"] = "cache:";
SearchOperator["Define"] = "define:";
SearchOperator["Related"] = "related:";
SearchOperator["Link"] = "link:";
SearchOperator["Ext"] = "ext:";
SearchOperator["Location"] = "location:";
SearchOperator["Region"] = "region:";
SearchOperator["Language"] = "language:";
SearchOperator["Feed"] = "feed:";
SearchOperator["HasFeed"] = "hasfeed:";
SearchOperator["IPAddress"] = "ip:";
SearchOperator["Prefer"] = "prefer:";
SearchOperator["AllInTitle"] = "allintitle:";
SearchOperator["AllInUrl"] = "allinurl:";
SearchOperator["AllInText"] = "allintext:";
SearchOperator["AllInAnchor"] = "allinanchor:";
})(SearchOperator = exports.SearchOperator || (exports.SearchOperator = {}));
exports.OPERATOR_INFO = {
site: {
description: 'Search within a specific website or domain',
example: 'site:example.com',
placeholder: 'example.com',
},
filetype: {
description: 'Search for specific file types',
example: 'filetype:pdf',
placeholder: 'pdf, doc, xls, ppt, etc.',
},
intitle: {
description: 'Search for pages with specific words in the title',
example: 'intitle:important',
placeholder: 'words to find in title',
},
inurl: {
description: 'Search for pages with specific words in the URL',
example: 'inurl:api',
placeholder: 'words to find in URL',
},
inbody: {
description: 'Search for pages with specific words in the body text',
example: 'inbody:content',
placeholder: 'words to find in body',
},
cache: {
description: 'View the cached version of a webpage',
example: 'cache:example.com',
placeholder: 'example.com',
},
define: {
description: 'Get definitions for a word or phrase',
example: 'define:quantum',
placeholder: 'word to define',
},
related: {
description: 'Find websites related to a specific URL',
example: 'related:example.com',
placeholder: 'example.com',
},
link: {
description: 'Find pages that link to a specific URL',
example: 'link:example.com',
placeholder: 'example.com',
},
ext: {
description: 'Search for specific file extensions (alias for filetype)',
example: 'ext:pdf',
placeholder: 'pdf, doc, etc.',
},
location: {
description: 'Search for results from a specific location',
example: 'location:"New York"',
placeholder: 'city or country',
},
region: {
description: 'Search for results from a specific region',
example: 'region:us',
placeholder: 'country code',
},
language: {
description: 'Search for results in a specific language',
example: 'language:en',
placeholder: 'language code',
},
feed: {
description: 'Find RSS or Atom feeds',
example: 'feed:blog',
placeholder: 'feed keyword',
},
hasfeed: {
description: 'Find pages that have RSS or Atom feeds',
example: 'hasfeed:news',
placeholder: 'keyword',
},
ip: {
description: 'Search for information about an IP address',
example: 'ip:192.168.1.1',
placeholder: 'IP address',
},
prefer: {
description: 'Prefer newer or older results',
example: 'prefer:newer',
placeholder: 'newer or older',
},
allintitle: {
description: 'All words must appear in the title',
example: 'allintitle:important news',
placeholder: 'all words for title',
},
allinurl: {
description: 'All words must appear in the URL',
example: 'allinurl:api docs',
placeholder: 'all words for URL',
},
allintext: {
description: 'All words must appear in the text',
example: 'allintext:complete guide',
placeholder: 'all words for text',
},
allinanchor: {
description: 'All words must appear in anchor text',
example: 'allinanchor:click here',
placeholder: 'all words for anchors',
},
exclude: {
description: 'Exclude results containing specific words (use - prefix)',
example: '-unwanted',
placeholder: 'words to exclude',
},
exact: {
description: 'Search for exact phrase (use quotes)',
example: '"exact phrase"',
placeholder: 'exact phrase to match',
},
or: {
description: 'Search for any of the specified terms (use OR)',
example: 'term1 OR term2',
placeholder: 'alternative terms',
},
};
function buildSearchQuery(baseQuery, operators) {
if (!operators || Object.keys(operators).length === 0) {
return baseQuery;
}
const queryParts = [];
if (baseQuery.trim()) {
queryParts.push(baseQuery);
}
if (operators.site) {
queryParts.push(`site:${operators.site}`);
}
if (operators.filetype) {
queryParts.push(`filetype:${operators.filetype}`);
}
if (operators.intitle) {
queryParts.push(`intitle:${operators.intitle}`);
}
if (operators.inurl) {
queryParts.push(`inurl:${operators.inurl}`);
}
if (operators.inbody) {
queryParts.push(`inbody:${operators.inbody}`);
}
if (operators.cache) {
queryParts.push(`cache:${operators.cache}`);
}
if (operators.define) {
queryParts.push(`define:${operators.define}`);
}
if (operators.related) {
queryParts.push(`related:${operators.related}`);
}
if (operators.link) {
queryParts.push(`link:${operators.link}`);
}
if (operators.ext) {
queryParts.push(`ext:${operators.ext}`);
}
if (operators.location) {
const location = operators.location.includes(' ') ? `"${operators.location}"` : operators.location;
queryParts.push(`location:${location}`);
}
if (operators.region) {
queryParts.push(`region:${operators.region}`);
}
if (operators.language) {
queryParts.push(`language:${operators.language}`);
}
if (operators.feed) {
queryParts.push(`feed:${operators.feed}`);
}
if (operators.hasfeed) {
queryParts.push(`hasfeed:${operators.hasfeed}`);
}
if (operators.ip) {
queryParts.push(`ip:${operators.ip}`);
}
if (operators.prefer) {
queryParts.push(`prefer:${operators.prefer}`);
}
if (operators.allintitle) {
queryParts.push(`allintitle:${operators.allintitle}`);
}
if (operators.allinurl) {
queryParts.push(`allinurl:${operators.allinurl}`);
}
if (operators.allintext) {
queryParts.push(`allintext:${operators.allintext}`);
}
if (operators.allinanchor) {
queryParts.push(`allinanchor:${operators.allinanchor}`);
}
if (operators.exclude) {
const exclusions = operators.exclude.split(',').map(e => e.trim());
exclusions.forEach(exclusion => {
if (exclusion && !exclusion.startsWith('-')) {
queryParts.push(`-${exclusion}`);
}
else if (exclusion) {
queryParts.push(exclusion);
}
});
}
if (operators.exact) {
const exactPhrase = operators.exact.trim();
if (exactPhrase && !exactPhrase.startsWith('"')) {
queryParts.push(`"${exactPhrase}"`);
}
else if (exactPhrase) {
queryParts.push(exactPhrase);
}
}
if (operators.or && operators.or.length > 0) {
const orQuery = operators.or.filter(term => term.trim()).join(' OR ');
if (orQuery) {
queryParts.push(`(${orQuery})`);
}
}
return queryParts.join(' ');
}
exports.buildSearchQuery = buildSearchQuery;
function parseSearchOperators(query) {
const operators = {};
const removals = [];
const markForRemoval = (startIndex, length) => {
removals.push({ start: startIndex, end: startIndex + length });
};
const operatorRegex = /(\w+):("(?:[^"\\]|\\.)*"|\S+)/g;
let match;
while ((match = operatorRegex.exec(query)) !== null) {
if (!match || !match[1] || !match[2])
continue;
const [fullMatch, operator, value] = match;
const cleanValue = value.replace(/^"|"$/g, '');
switch (operator.toLowerCase()) {
case 'site':
operators.site = cleanValue;
break;
case 'filetype':
operators.filetype = cleanValue;
break;
case 'intitle':
operators.intitle = cleanValue;
break;
case 'inurl':
operators.inurl = cleanValue;
break;
case 'inbody':
operators.inbody = cleanValue;
break;
case 'cache':
operators.cache = cleanValue;
break;
case 'define':
operators.define = cleanValue;
break;
case 'related':
operators.related = cleanValue;
break;
case 'link':
operators.link = cleanValue;
break;
case 'ext':
operators.ext = cleanValue;
break;
case 'location':
operators.location = cleanValue;
break;
case 'region':
operators.region = cleanValue;
break;
case 'language':
operators.language = cleanValue;
break;
case 'feed':
operators.feed = cleanValue;
break;
case 'hasfeed':
operators.hasfeed = cleanValue;
break;
case 'ip':
operators.ip = cleanValue;
break;
case 'prefer':
operators.prefer = cleanValue;
break;
case 'allintitle':
operators.allintitle = cleanValue;
break;
case 'allinurl':
operators.allinurl = cleanValue;
break;
case 'allintext':
operators.allintext = cleanValue;
break;
case 'allinanchor':
operators.allinanchor = cleanValue;
break;
}
if (match.index !== undefined) {
markForRemoval(match.index, fullMatch.length);
}
}
const exclusions = [];
const exclusionRegex = /(?:^|\s)-(\w+)(?=\s|$)/g;
while ((match = exclusionRegex.exec(query)) !== null) {
if (match && match[1] && match.index !== undefined) {
exclusions.push(match[1]);
markForRemoval(match.index, match[0].length);
}
}
if (exclusions.length > 0) {
operators.exclude = exclusions.join(', ');
}
const exactPhrases = [];
const exactRegex = /"([^"]+)"/g;
while ((match = exactRegex.exec(query)) !== null) {
if (match && match[1] && match.index !== undefined) {
const beforeIndex = match.index - 1;
if (beforeIndex < 0 || query[beforeIndex] !== ':') {
exactPhrases.push(match[1]);
markForRemoval(match.index, match[0].length);
}
}
}
if (exactPhrases.length > 0) {
operators.exact = exactPhrases.join(' ');
}
const orTerms = [];
const orRegex = /(\w+)\s+OR\s+(\w+)/g;
while ((match = orRegex.exec(query)) !== null) {
if (match && match[1] && match[2] && match.index !== undefined) {
orTerms.push(match[1], match[2]);
markForRemoval(match.index, match[0].length);
}
}
if (orTerms.length > 0) {
operators.or = [...new Set(orTerms)];
}
removals.sort((a, b) => b.start - a.start);
const queryChars = query.split('');
removals.forEach(removal => {
queryChars.splice(removal.start, removal.end - removal.start);
});
let baseQuery = queryChars.join('');
baseQuery = baseQuery.replace(/\s+/g, ' ').trim();
return { baseQuery, operators };
}
exports.parseSearchOperators = parseSearchOperators;
function validateSearchOperators(operators) {
const errors = [];
if (operators.filetype) {
const validFileTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf', 'odt', 'html', 'htm', 'xml', 'json', 'csv', 'zip', 'rar', '7z', 'tar', 'gz'];
if (!validFileTypes.includes(operators.filetype.toLowerCase())) {
errors.push(`Invalid filetype: ${operators.filetype}. Valid types: ${validFileTypes.join(', ')}`);
}
}
if (operators.region) {
const validRegions = ['us', 'uk', 'ca', 'au', 'de', 'fr', 'es', 'it', 'nl', 'br', 'mx', 'ar', 'in', 'jp', 'cn', 'kr', 'ru'];
if (!validRegions.includes(operators.region.toLowerCase())) {
errors.push(`Invalid region: ${operators.region}. Valid regions: ${validRegions.join(', ')}`);
}
}
if (operators.language) {
const validLanguages = ['en', 'es', 'fr', 'de', 'it', 'pt', 'nl', 'ru', 'ja', 'zh', 'ko', 'ar', 'hi', 'tr', 'pl', 'sv', 'da', 'no', 'fi'];
if (!validLanguages.includes(operators.language.toLowerCase())) {
errors.push(`Invalid language: ${operators.language}. Valid languages: ${validLanguages.join(', ')}`);
}
}
if (operators.prefer && !['newer', 'older'].includes(operators.prefer.toLowerCase())) {
errors.push(`Invalid prefer value: ${operators.prefer}. Use 'newer' or 'older'`);
}
if (operators.ip) {
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
if (!ipRegex.test(operators.ip)) {
errors.push(`Invalid IP address format: ${operators.ip}`);
}
else {
const octets = operators.ip.split('.');
const invalidOctets = octets.filter(octet => {
const num = parseInt(octet, 10);
return num > 255;
});
if (invalidOctets.length > 0) {
errors.push(`Invalid IP address format: ${operators.ip}`);
}
}
}
return errors;
}
exports.validateSearchOperators = validateSearchOperators;