]+class="[^"]*result__snippet[^"]*"[^>]*>([\s\S]*?)<\/a>|]+class="[^"]*result__snippet[^"]*"[^>]*>([\s\S]*?)<\/div>)?/gi;
let match;
while ((match = resultRegex.exec(html)) && results.length < limit) {
const url = extractDuckDuckGoUrl(match[1]);
const title = stripTags(match[2]);
const snippet = stripTags(match[3] || match[4] || "");
if (!url || !title || results.some((item) => item.url === url)) continue;
results.push({ title, url, snippet, provider: "duckduckgo" });
}
return results;
}
function normalizeTimeFilter(timeFilter) {
const value = String(timeFilter || "any").toLowerCase();
if (value === "day") return "d";
if (value === "week") return "w";
if (value === "month") return "m";
if (value === "year") return "y";
return "";
}
async function searchDuckDuckGo(query, options = {}) {
const limit = Math.max(1, Math.min(10, Number(options.limit) || 5));
const params = new URLSearchParams({
q: String(query || "").trim(),
kl: "us-en",
});
const df = normalizeTimeFilter(options.timeFilter);
if (df) params.set("df", df);
const html = await requestText(`https://html.duckduckgo.com/html/?${params.toString()}`);
return parseDuckDuckGoHtml(html, limit);
}
async function webSearch(query, options = {}) {
const trimmed = String(query || "").trim();
if (!trimmed) return [];
return searchDuckDuckGo(trimmed, options);
}
module.exports = {
webSearch,
};