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.
194 lines (193 loc) • 8.12 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fallbackVideoSearch = exports.fallbackNewsSearch = exports.fallbackImageSearch = exports.fallbackWebSearch = exports.searchVideosWithFallback = exports.searchNewsWithFallback = exports.searchWithFallback = void 0;
const duck_duck_scrape_1 = require("duck-duck-scrape");
const apiClient_1 = require("./apiClient");
const axios_1 = __importDefault(require("axios"));
async function searchWithFallback(query, options = {}) {
try {
const result = await (0, duck_duck_scrape_1.search)(query, options);
if (result && result.results && result.results.length > 0) {
return result;
}
console.warn('Duck-duck-scrape returned no results, falling back to SearchAPI');
return await (0, apiClient_1.searchWithAPI)(query, options);
}
catch (error) {
console.warn(`Duck-duck-scrape failed: ${error.message}, falling back to SearchAPI`);
try {
return await (0, apiClient_1.searchWithAPI)(query, options);
}
catch (fallbackError) {
throw new Error(`Both search methods failed. SearchAPI error: ${fallbackError.message}`);
}
}
}
exports.searchWithFallback = searchWithFallback;
async function searchNewsWithFallback(query, options = {}) {
try {
const result = await (0, duck_duck_scrape_1.searchNews)(query, options);
if (result && result.results && result.results.length > 0) {
return result;
}
console.warn('Duck-duck-scrape news returned no results, falling back to SearchAPI');
return await (0, apiClient_1.searchNewsWithAPI)(query, options);
}
catch (error) {
console.warn(`Duck-duck-scrape news failed: ${error.message}, falling back to SearchAPI`);
try {
return await (0, apiClient_1.searchNewsWithAPI)(query, options);
}
catch (fallbackError) {
throw new Error(`Both news search methods failed. SearchAPI error: ${fallbackError.message}`);
}
}
}
exports.searchNewsWithFallback = searchNewsWithFallback;
async function searchVideosWithFallback(query, options = {}) {
try {
const result = await (0, duck_duck_scrape_1.searchVideos)(query, options);
if (result && result.results && result.results.length > 0) {
return result;
}
console.warn('Duck-duck-scrape videos returned no results, falling back to SearchAPI');
return await (0, apiClient_1.searchVideosWithAPI)(query, options);
}
catch (error) {
console.warn(`Duck-duck-scrape videos failed: ${error.message}, falling back to SearchAPI`);
try {
return await (0, apiClient_1.searchVideosWithAPI)(query, options);
}
catch (fallbackError) {
throw new Error(`Both video search methods failed. SearchAPI error: ${fallbackError.message}`);
}
}
}
exports.searchVideosWithFallback = searchVideosWithFallback;
function parseSearchResultsFromHTML(html) {
const results = [];
const resultRegex = /<div[^>]*class="[^"]*result[^"]*"[^>]*>([\s\S]*?)<\/div>/gi;
const titleRegex = /<a[^>]*class="[^"]*result__a[^"]*"[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/i;
const snippetRegex = /<[^>]*class="[^"]*result__snippet[^"]*"[^>]*>(.*?)<\/[^>]*>/i;
let match;
while ((match = resultRegex.exec(html)) !== null) {
const resultHTML = match[1];
const titleMatch = titleRegex.exec(resultHTML);
const snippetMatch = snippetRegex.exec(resultHTML);
if (titleMatch) {
const href = titleMatch[1];
const title = titleMatch[2].replace(/<[^>]*>/g, '').trim();
const body = snippetMatch ? snippetMatch[1].replace(/<[^>]*>/g, '').trim() : '';
if (title && href) {
results.push({
title: cleanText(title),
href: href.startsWith('http') ? href : `https://${href}`,
body: cleanText(body),
});
}
}
}
return results;
}
function cleanText(text) {
return text
.replace(/ /g, ' ')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/\s+/g, ' ')
.trim();
}
async function fallbackWebSearch(query, options = {}) {
try {
const searchUrl = 'https://html.duckduckgo.com/html/';
const params = new URLSearchParams({
q: query,
kl: options.locale || 'us-en',
s: String(options.safeSearch || 'moderate'),
df: options.time || '',
});
const response = await axios_1.default.get(`${searchUrl}?${params.toString()}`, {
headers: {
'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',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
'DNT': '1',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
},
timeout: 10000,
});
const results = parseSearchResultsFromHTML(response.data);
const noResultsIndicator = response.data.includes('no-results') || results.length === 0;
return {
success: true,
noResults: noResultsIndicator,
results,
};
}
catch (error) {
console.error('Fallback search error:', error);
return {
success: false,
noResults: true,
results: [],
error: `Fallback search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
}
exports.fallbackWebSearch = fallbackWebSearch;
async function fallbackImageSearch(query, options = {}) {
try {
const imageQuery = `${query} images photos pictures`;
return await fallbackWebSearch(imageQuery, options);
}
catch (error) {
console.error('Fallback image search error:', error);
return {
success: false,
noResults: true,
results: [],
error: `Fallback image search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
}
exports.fallbackImageSearch = fallbackImageSearch;
async function fallbackNewsSearch(query, options = {}) {
try {
const newsQuery = `${query} site:news.com OR site:bbc.com OR site:cnn.com OR site:reuters.com`;
return await fallbackWebSearch(newsQuery, options);
}
catch (error) {
console.error('Fallback news search error:', error);
return {
success: false,
noResults: true,
results: [],
error: `Fallback news search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
}
exports.fallbackNewsSearch = fallbackNewsSearch;
async function fallbackVideoSearch(query, options = {}) {
try {
const videoQuery = `${query} site:youtube.com OR site:vimeo.com OR site:dailymotion.com`;
return await fallbackWebSearch(videoQuery, options);
}
catch (error) {
console.error('Fallback video search error:', error);
return {
success: false,
noResults: true,
results: [],
error: `Fallback video search failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
};
}
}
exports.fallbackVideoSearch = fallbackVideoSearch;