n8n-nodes-deep-research 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +190 -0
- package/dist/nodes/DeepResearch/DeepResearch.dark.svg +10 -0
- package/dist/nodes/DeepResearch/DeepResearch.node.d.ts +5 -0
- package/dist/nodes/DeepResearch/DeepResearch.node.js +1130 -0
- package/dist/nodes/DeepResearch/DeepResearch.node.js.map +1 -0
- package/dist/nodes/DeepResearch/DeepResearch.svg +10 -0
- package/dist/package.json +72 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeepResearch = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const USER_AGENTS = [
|
|
6
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
7
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
8
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0',
|
|
9
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15',
|
|
10
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
|
|
11
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
|
|
12
|
+
'Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0',
|
|
13
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
|
|
14
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 OPR/114.0.0.0',
|
|
15
|
+
'Mozilla/5.0 (iPhone; CPU iPhone OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1 Mobile/15E148 Safari/604.1',
|
|
16
|
+
'Mozilla/5.0 (iPad; CPU OS 18_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/131.0.6778.73 Mobile/15E148 Safari/604.1',
|
|
17
|
+
'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Mobile Safari/537.36',
|
|
18
|
+
];
|
|
19
|
+
function randomUa() {
|
|
20
|
+
return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
|
|
21
|
+
}
|
|
22
|
+
function randomDelay(minMs = 500, maxMs = 2000) {
|
|
23
|
+
const ms = Math.floor(Math.random() * (maxMs - minMs + 1)) + minMs;
|
|
24
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
25
|
+
}
|
|
26
|
+
async function retryRequest(ctx, options, maxRetries = 2) {
|
|
27
|
+
let lastError;
|
|
28
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
29
|
+
try {
|
|
30
|
+
if (attempt > 0) {
|
|
31
|
+
await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt) + Math.random() * 1000));
|
|
32
|
+
}
|
|
33
|
+
return await ctx.helpers.httpRequest(options);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
lastError = err;
|
|
37
|
+
if (attempt === maxRetries)
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw lastError;
|
|
42
|
+
}
|
|
43
|
+
function stripHtml(raw) {
|
|
44
|
+
return raw
|
|
45
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
|
46
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
47
|
+
.replace(/<[^>]+>/g, ' ')
|
|
48
|
+
.replace(/ /g, ' ')
|
|
49
|
+
.replace(/&/g, '&')
|
|
50
|
+
.replace(/</g, '<')
|
|
51
|
+
.replace(/>/g, '>')
|
|
52
|
+
.replace(/"/g, '"')
|
|
53
|
+
.replace(/'/g, "'")
|
|
54
|
+
.replace(/'/g, "'")
|
|
55
|
+
.replace(/—/g, '\u2014')
|
|
56
|
+
.replace(/–/g, '\u2013')
|
|
57
|
+
.replace(/’/g, "'")
|
|
58
|
+
.replace(/‘/g, "'")
|
|
59
|
+
.replace(/”/g, '"')
|
|
60
|
+
.replace(/“/g, '"')
|
|
61
|
+
.replace(/'/g, "'")
|
|
62
|
+
.replace(///g, '/')
|
|
63
|
+
.replace(/\s{2,}/g, ' ')
|
|
64
|
+
.trim();
|
|
65
|
+
}
|
|
66
|
+
function decodeEnt(str) {
|
|
67
|
+
return str
|
|
68
|
+
.replace(/ /g, ' ')
|
|
69
|
+
.replace(/&/g, '&')
|
|
70
|
+
.replace(/</g, '<')
|
|
71
|
+
.replace(/>/g, '>')
|
|
72
|
+
.replace(/"/g, '"')
|
|
73
|
+
.replace(/'/g, "'")
|
|
74
|
+
.replace(/'/g, "'");
|
|
75
|
+
}
|
|
76
|
+
function htmlRequestOpts(url, extra = {}) {
|
|
77
|
+
return {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
url,
|
|
80
|
+
headers: {
|
|
81
|
+
'User-Agent': randomUa(),
|
|
82
|
+
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
83
|
+
'Accept-Language': 'en-US,en;q=0.9',
|
|
84
|
+
'Accept-Encoding': 'gzip, deflate',
|
|
85
|
+
Connection: 'keep-alive',
|
|
86
|
+
...extra,
|
|
87
|
+
},
|
|
88
|
+
timeout: 20000,
|
|
89
|
+
returnFullResponse: false,
|
|
90
|
+
json: false,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function jsonRequestOpts(url, extra = {}) {
|
|
94
|
+
return {
|
|
95
|
+
method: 'GET',
|
|
96
|
+
url,
|
|
97
|
+
headers: {
|
|
98
|
+
'User-Agent': 'n8n-deep-research/1.0',
|
|
99
|
+
Accept: 'application/json',
|
|
100
|
+
...extra,
|
|
101
|
+
},
|
|
102
|
+
timeout: 20000,
|
|
103
|
+
returnFullResponse: false,
|
|
104
|
+
json: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async function searchDuckDuckGo(ctx, query, max) {
|
|
108
|
+
var _a;
|
|
109
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
110
|
+
const response = (await retryRequest(ctx, htmlRequestOpts(url)));
|
|
111
|
+
const results = [];
|
|
112
|
+
const blocks = response.split('class="result__body"');
|
|
113
|
+
for (let i = 1; i < blocks.length && results.length < max; i++) {
|
|
114
|
+
const b = blocks[i];
|
|
115
|
+
const hm = b.match(/href="(https?:\/\/[^"]+)"/);
|
|
116
|
+
let itemUrl = '';
|
|
117
|
+
if (hm) {
|
|
118
|
+
const um = hm[1].match(/uddg=([^&]+)/);
|
|
119
|
+
itemUrl = um ? decodeURIComponent(um[1]) : hm[1];
|
|
120
|
+
}
|
|
121
|
+
const tm = b.match(/class="result__a"[^>]*>([\s\S]*?)<\/a>/);
|
|
122
|
+
const sm = b.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
|
|
123
|
+
if (((_a = tm === null || tm === void 0 ? void 0 : tm[1]) === null || _a === void 0 ? void 0 : _a.trim()) && itemUrl) {
|
|
124
|
+
results.push({ title: decodeEnt(stripHtml(tm[1])), url: itemUrl, snippet: sm ? decodeEnt(stripHtml(sm[1])) : '', source: 'duckduckgo' });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return results;
|
|
128
|
+
}
|
|
129
|
+
async function searchReddit(ctx, query, max, sort, time) {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
const url = `https://www.reddit.com/search.json?q=${encodeURIComponent(query)}&limit=${max}&sort=${sort}&t=${time}&raw_json=1`;
|
|
132
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url)));
|
|
133
|
+
const results = [];
|
|
134
|
+
const children = (_b = (_a = data.data) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [];
|
|
135
|
+
for (const c of children) {
|
|
136
|
+
if (results.length >= max)
|
|
137
|
+
break;
|
|
138
|
+
const p = c.data;
|
|
139
|
+
if (!p || p.over_18)
|
|
140
|
+
continue;
|
|
141
|
+
const selftext = p.selftext ? stripHtml(p.selftext).substring(0, 500) : '';
|
|
142
|
+
results.push({
|
|
143
|
+
title: p.title || '', url: `https://reddit.com${p.permalink}`,
|
|
144
|
+
snippet: selftext || p.title, source: 'reddit',
|
|
145
|
+
redditScore: p.score, redditAuthor: p.author,
|
|
146
|
+
redditSubreddit: p.subreddit, redditNumComments: p.num_comments,
|
|
147
|
+
redditCreatedUtc: p.created_utc ? new Date(p.created_utc * 1000).toISOString() : undefined,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return results;
|
|
151
|
+
}
|
|
152
|
+
async function searchHackerNews(ctx, query, max, byDate, tags) {
|
|
153
|
+
var _a, _b, _c;
|
|
154
|
+
const url = `https://hn.algolia.com/api/v1/search?query=${encodeURIComponent(query)}&hitsPerPage=${max}&sort=${byDate ? 'by_date' : 'relevance'}&tags=${tags}`;
|
|
155
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url)));
|
|
156
|
+
const results = [];
|
|
157
|
+
for (const h of ((_a = data.hits) !== null && _a !== void 0 ? _a : [])) {
|
|
158
|
+
if (results.length >= max)
|
|
159
|
+
break;
|
|
160
|
+
results.push({
|
|
161
|
+
title: h.title || h.story_title || '',
|
|
162
|
+
url: h.url || `https://news.ycombinator.com/item?id=${h.objectID}`,
|
|
163
|
+
snippet: h.author ? `by ${h.author} | points: ${(_b = h.points) !== null && _b !== void 0 ? _b : 0} | comments: ${(_c = h.num_comments) !== null && _c !== void 0 ? _c : 0}` : '',
|
|
164
|
+
source: 'hackernews', hnPoints: h.points, hnAuthor: h.author,
|
|
165
|
+
hnNumComments: h.num_comments, hnCreated: h.created_at,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return results;
|
|
169
|
+
}
|
|
170
|
+
async function searchWikipedia(ctx, query, max, lang, extracts) {
|
|
171
|
+
var _a, _b;
|
|
172
|
+
const url = `https://${lang}.wikipedia.org/w/api.php?action=query&list=search&srsearch=${encodeURIComponent(query)}&format=json&srlimit=${max}`;
|
|
173
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url)));
|
|
174
|
+
const results = [];
|
|
175
|
+
const qd = data.query;
|
|
176
|
+
for (const i of ((_a = qd === null || qd === void 0 ? void 0 : qd.search) !== null && _a !== void 0 ? _a : [])) {
|
|
177
|
+
if (results.length >= max)
|
|
178
|
+
break;
|
|
179
|
+
results.push({
|
|
180
|
+
title: i.title,
|
|
181
|
+
url: `https://${lang}.wikipedia.org/wiki/${encodeURIComponent(i.title.replace(/ /g, '_'))}`,
|
|
182
|
+
snippet: i.snippet ? decodeEnt(stripHtml(i.snippet)) : '', source: 'wikipedia',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (extracts && results.length > 0) {
|
|
186
|
+
try {
|
|
187
|
+
const titles = results.map((r) => r.title).join('|');
|
|
188
|
+
const eu = `https://${lang}.wikipedia.org/w/api.php?action=query&titles=${encodeURIComponent(titles)}&prop=extracts&exintro&explaintext&exsentences=5&format=json`;
|
|
189
|
+
const ed = (await retryRequest(ctx, jsonRequestOpts(eu)));
|
|
190
|
+
const eq = ed.query;
|
|
191
|
+
const pages = (_b = eq === null || eq === void 0 ? void 0 : eq.pages) !== null && _b !== void 0 ? _b : {};
|
|
192
|
+
for (const pid of Object.keys(pages)) {
|
|
193
|
+
const pg = pages[pid];
|
|
194
|
+
if (pg.extract) {
|
|
195
|
+
const f = results.find((r) => r.title === pg.title);
|
|
196
|
+
if (f)
|
|
197
|
+
f.snippet = pg.extract;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (_e) { }
|
|
202
|
+
}
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
async function searchNewsRSS(ctx, query, max, source) {
|
|
206
|
+
const rssUrls = {
|
|
207
|
+
google: `https://news.google.com/rss/search?q=${encodeURIComponent(query)}`,
|
|
208
|
+
techcrunch: `https://techcrunch.com/feed/?s=${encodeURIComponent(query)}`,
|
|
209
|
+
bbc: `https://feeds.bbci.co.uk/news/search/rss?query=${encodeURIComponent(query)}`,
|
|
210
|
+
reuters: `https://feeds.reuters.com/reuters/topNews`,
|
|
211
|
+
custom: query,
|
|
212
|
+
};
|
|
213
|
+
const rssUrl = rssUrls[source] || rssUrls.google;
|
|
214
|
+
const xml = (await retryRequest(ctx, {
|
|
215
|
+
...jsonRequestOpts(rssUrl), json: false,
|
|
216
|
+
headers: { 'User-Agent': 'n8n-deep-research/1.0', Accept: 'application/rss+xml, application/xml, text/xml' },
|
|
217
|
+
}));
|
|
218
|
+
const results = [];
|
|
219
|
+
const rx = /<item>([\s\S]*?)<\/item>/gi;
|
|
220
|
+
let m;
|
|
221
|
+
while ((m = rx.exec(xml)) !== null && results.length < max) {
|
|
222
|
+
const ix = m[1];
|
|
223
|
+
const tm = ix.match(/<title>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/title>/i);
|
|
224
|
+
const lm = ix.match(/<link>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/link>/i);
|
|
225
|
+
const dm = ix.match(/<description>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/description>/i);
|
|
226
|
+
const pm = ix.match(/<pubDate>([\s\S]*?)<\/pubDate>/i);
|
|
227
|
+
if ((tm === null || tm === void 0 ? void 0 : tm[1]) && (lm === null || lm === void 0 ? void 0 : lm[1])) {
|
|
228
|
+
const r = { title: decodeEnt(stripHtml(tm[1])), url: decodeEnt(stripHtml(lm[1])), snippet: dm ? decodeEnt(stripHtml(dm[1])) : '', source: `news-${source}` };
|
|
229
|
+
if (pm)
|
|
230
|
+
r.publishedAt = pm[1].trim();
|
|
231
|
+
results.push(r);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return results;
|
|
235
|
+
}
|
|
236
|
+
async function searchGitHub(ctx, query, max, type, sort) {
|
|
237
|
+
var _a;
|
|
238
|
+
const sp = sort ? `&sort=${sort}` : '';
|
|
239
|
+
const url = `https://api.github.com/search/${type}?q=${encodeURIComponent(query)}&per_page=${max}${sp}`;
|
|
240
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url, { Accept: 'application/vnd.github.v3+json' })));
|
|
241
|
+
const results = [];
|
|
242
|
+
for (const i of ((_a = data.items) !== null && _a !== void 0 ? _a : [])) {
|
|
243
|
+
if (results.length >= max)
|
|
244
|
+
break;
|
|
245
|
+
if (type === 'repositories') {
|
|
246
|
+
results.push({ title: i.full_name || i.name, url: i.html_url, snippet: i.description || '', source: 'github', githubStars: i.stargazers_count, githubForks: i.forks_count, githubLanguage: i.language });
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
results.push({ title: i.title || i.name || i.path || '', url: i.html_url, snippet: i.body ? stripHtml(i.body).substring(0, 500) : '', source: 'github' });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return results;
|
|
253
|
+
}
|
|
254
|
+
async function scrapeWebPage(ctx, targetUrl, extractLinks, maxLen) {
|
|
255
|
+
var _a, _b, _c, _d, _f, _g;
|
|
256
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(targetUrl)));
|
|
257
|
+
const title = ((_a = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i)) !== null && _a !== void 0 ? _a : [])[1] ? decodeEnt(stripHtml(((_b = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i)) !== null && _b !== void 0 ? _b : [])[1])) : '';
|
|
258
|
+
const desc = (((_c = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']+)["']/i)) !== null && _c !== void 0 ? _c : [])[1]) || '';
|
|
259
|
+
const ogTitle = (((_d = html.match(/<meta\s+(?:property|name)=["']og:title["']\s+content=["']([^"']+)["']/i)) !== null && _d !== void 0 ? _d : [])[1]) || '';
|
|
260
|
+
const ogDesc = (((_f = html.match(/<meta\s+(?:property|name)=["']og:description["']\s+content=["']([^"']+)["']/i)) !== null && _f !== void 0 ? _f : [])[1]) || '';
|
|
261
|
+
const ogImg = (((_g = html.match(/<meta\s+(?:property|name)=["']og:image["']\s+content=["']([^"']+)["']/i)) !== null && _g !== void 0 ? _g : [])[1]) || '';
|
|
262
|
+
let textContent = stripHtml(html);
|
|
263
|
+
if (textContent.length > maxLen)
|
|
264
|
+
textContent = textContent.substring(0, maxLen) + '... [truncated]';
|
|
265
|
+
const result = { title, url: targetUrl, snippet: desc || ogDesc, source: 'web-scrape', description: desc, ogTitle, ogDescription: ogDesc, ogImage: ogImg, textContent, textLength: stripHtml(html).length };
|
|
266
|
+
if (extractLinks) {
|
|
267
|
+
const lr = /href=["'](https?:\/\/[^"']+)["']/gi;
|
|
268
|
+
const links = [];
|
|
269
|
+
let lm;
|
|
270
|
+
while ((lm = lr.exec(html)) !== null) {
|
|
271
|
+
if (!lm[1].includes('#') && !lm[1].includes('javascript:'))
|
|
272
|
+
links.push(lm[1]);
|
|
273
|
+
}
|
|
274
|
+
const ul = [...new Set(links)];
|
|
275
|
+
result.links = ul;
|
|
276
|
+
result.linksCount = ul.length;
|
|
277
|
+
}
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
const NITTER_INSTANCES = [
|
|
281
|
+
'nitter.privacydev.net', 'nitter.poast.org', 'nitter.woodland.cafe',
|
|
282
|
+
'bird.trom.tf', 'nitter.projectsegfau.lt',
|
|
283
|
+
];
|
|
284
|
+
async function searchTwitter(ctx, query, max) {
|
|
285
|
+
const results = [];
|
|
286
|
+
try {
|
|
287
|
+
const url = `https://fixupx.com/search?q=${encodeURIComponent(query)}&f=live`;
|
|
288
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url), 2));
|
|
289
|
+
const tweetRegex = /<article[^>]*>([\s\S]*?)<\/article>/gi;
|
|
290
|
+
let tm;
|
|
291
|
+
while ((tm = tweetRegex.exec(html)) !== null && results.length < max) {
|
|
292
|
+
const block = tm[1];
|
|
293
|
+
const textM = block.match(/<div[^>]*class="[^"]*tweet-text[^"]*"[^>]*>([\s\S]*?)<\/div>/i);
|
|
294
|
+
const userM = block.match(/<a[^>]*class="[^"]*username[^"]*"[^>]*>([\s\S]*?)<\/a>/i);
|
|
295
|
+
const linkM = block.match(/href="(\/[^"]*\/status\/\d+)"/i);
|
|
296
|
+
if (textM) {
|
|
297
|
+
const text = stripHtml(textM[1]).substring(0, 300);
|
|
298
|
+
const user = userM ? stripHtml(userM[1]) : '';
|
|
299
|
+
const tweetUrl = linkM ? `https://x.com${linkM[1]}` : `https://x.com/search?q=${encodeURIComponent(query)}`;
|
|
300
|
+
results.push({ title: `${user}: ${text.substring(0, 80)}`, url: tweetUrl, snippet: text, source: 'twitter', twitterUser: user });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (_e) { }
|
|
305
|
+
await randomDelay(800, 1500);
|
|
306
|
+
if (results.length < max) {
|
|
307
|
+
for (const instance of NITTER_INSTANCES) {
|
|
308
|
+
if (results.length >= max)
|
|
309
|
+
break;
|
|
310
|
+
try {
|
|
311
|
+
const rssUrl = `https://${instance}/search/rss?f=tweets&q=${encodeURIComponent(query)}`;
|
|
312
|
+
const xml = (await retryRequest(ctx, {
|
|
313
|
+
...jsonRequestOpts(rssUrl), json: false,
|
|
314
|
+
headers: { 'User-Agent': randomUa(), Accept: 'application/rss+xml' },
|
|
315
|
+
}, 1));
|
|
316
|
+
const itemRx = /<item>([\s\S]*?)<\/item>/gi;
|
|
317
|
+
let im;
|
|
318
|
+
while ((im = itemRx.exec(xml)) !== null && results.length < max) {
|
|
319
|
+
const ix = im[1];
|
|
320
|
+
const titM = ix.match(/<title>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/title>/i);
|
|
321
|
+
const lnkM = ix.match(/<link>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/link>/i);
|
|
322
|
+
const dscM = ix.match(/<description>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/description>/i);
|
|
323
|
+
if ((titM === null || titM === void 0 ? void 0 : titM[1]) && (lnkM === null || lnkM === void 0 ? void 0 : lnkM[1])) {
|
|
324
|
+
results.push({ title: decodeEnt(stripHtml(titM[1])), url: decodeEnt(stripHtml(lnkM[1])), snippet: dscM ? decodeEnt(stripHtml(dscM[1])) : '', source: 'twitter' });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch (_e) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
await randomDelay(500, 1000);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return results.slice(0, max);
|
|
335
|
+
}
|
|
336
|
+
async function searchQuora(ctx, query, max) {
|
|
337
|
+
const results = [];
|
|
338
|
+
try {
|
|
339
|
+
const url = `https://www.quora.com/search?q=${encodeURIComponent(query)}`;
|
|
340
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, {
|
|
341
|
+
'Accept': 'text/html,application/xhtml+xml',
|
|
342
|
+
'Sec-Fetch-Dest': 'document',
|
|
343
|
+
'Sec-Fetch-Mode': 'navigate',
|
|
344
|
+
}), 2));
|
|
345
|
+
const linkRx = /href="(\/(?!\/)[^"]*question\/[^"]*)"/gi;
|
|
346
|
+
const titleRx = /<span[^>]*class="[^"]*ui_qtext[^"]*"[^>]*>([\s\S]*?)<\/span>/gi;
|
|
347
|
+
const titles = [];
|
|
348
|
+
let tMatch;
|
|
349
|
+
while ((tMatch = titleRx.exec(html)) !== null && titles.length < max * 2) {
|
|
350
|
+
const t = stripHtml(tMatch[1]).trim();
|
|
351
|
+
if (t.length > 15)
|
|
352
|
+
titles.push(t);
|
|
353
|
+
}
|
|
354
|
+
let lMatch;
|
|
355
|
+
const seen = new Set();
|
|
356
|
+
let idx = 0;
|
|
357
|
+
while ((lMatch = linkRx.exec(html)) !== null && results.length < max) {
|
|
358
|
+
const fullUrl = `https://www.quora.com${lMatch[1]}`;
|
|
359
|
+
if (!seen.has(fullUrl)) {
|
|
360
|
+
seen.add(fullUrl);
|
|
361
|
+
results.push({ title: titles[idx] || 'Quora Question', url: fullUrl, snippet: '', source: 'quora' });
|
|
362
|
+
idx++;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch (_e) { }
|
|
367
|
+
return results;
|
|
368
|
+
}
|
|
369
|
+
const INVIDIOUS_INSTANCES = [
|
|
370
|
+
'inv.tux.pizza', 'vid.puffyan.us', 'invidious.fdn.fr',
|
|
371
|
+
'yewtu.be', 'invidious.nerdvpn.de', 'iv.ggtyler.dev',
|
|
372
|
+
];
|
|
373
|
+
async function searchYouTube(ctx, query, max) {
|
|
374
|
+
var _a;
|
|
375
|
+
const results = [];
|
|
376
|
+
for (const inst of INVIDIOUS_INSTANCES) {
|
|
377
|
+
if (results.length >= max)
|
|
378
|
+
break;
|
|
379
|
+
try {
|
|
380
|
+
const url = `https://${inst}/api/v1/search?q=${encodeURIComponent(query)}&type=video&sort_by=relevance&page=1`;
|
|
381
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url, { 'User-Agent': randomUa() }), 1));
|
|
382
|
+
if (Array.isArray(data)) {
|
|
383
|
+
for (const v of data) {
|
|
384
|
+
if (results.length >= max)
|
|
385
|
+
break;
|
|
386
|
+
if (v.type === 'video') {
|
|
387
|
+
results.push({
|
|
388
|
+
title: v.title || '', url: `https://www.youtube.com/watch?v=${v.videoId}`,
|
|
389
|
+
snippet: ((_a = v.description) === null || _a === void 0 ? void 0 : _a.substring(0, 300)) || '',
|
|
390
|
+
source: 'youtube', youtubeViews: v.viewCount,
|
|
391
|
+
youtubeAuthor: v.author || '', youtubeLengthSeconds: v.lengthSeconds,
|
|
392
|
+
youtubePublished: v.published,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
catch (_e) {
|
|
400
|
+
await randomDelay(300, 800);
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return results.slice(0, max);
|
|
405
|
+
}
|
|
406
|
+
async function searchStackExchange(ctx, query, max, site) {
|
|
407
|
+
var _a;
|
|
408
|
+
const url = `https://api.stackexchange.com/2.3/search/advanced?order=desc&sort=relevance&q=${encodeURIComponent(query)}&site=${site}&pagesize=${max}&filter=withbody`;
|
|
409
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url)));
|
|
410
|
+
const results = [];
|
|
411
|
+
for (const i of ((_a = data.items) !== null && _a !== void 0 ? _a : [])) {
|
|
412
|
+
if (results.length >= max)
|
|
413
|
+
break;
|
|
414
|
+
const body = i.body ? stripHtml(i.body).substring(0, 400) : '';
|
|
415
|
+
results.push({
|
|
416
|
+
title: i.title || '', url: i.link, snippet: body,
|
|
417
|
+
source: `stackexchange-${site}`, stackScore: i.score,
|
|
418
|
+
stackAnswers: i.answer_count, stackTags: i.tags,
|
|
419
|
+
stackIsAnswered: i.is_answered,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
return results;
|
|
423
|
+
}
|
|
424
|
+
async function searchMedium(ctx, query, max) {
|
|
425
|
+
var _a, _b, _c, _d, _f;
|
|
426
|
+
const results = [];
|
|
427
|
+
try {
|
|
428
|
+
const url = `https://medium.com/search?q=${encodeURIComponent(query)}`;
|
|
429
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, { Accept: 'text/html' }), 2));
|
|
430
|
+
const nextDataMatch = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/i);
|
|
431
|
+
if (nextDataMatch) {
|
|
432
|
+
try {
|
|
433
|
+
const nd = JSON.parse(nextDataMatch[1]);
|
|
434
|
+
const posts = ((_c = (_b = (_a = nd === null || nd === void 0 ? void 0 : nd.props) === null || _a === void 0 ? void 0 : _a.pageProps) === null || _b === void 0 ? void 0 : _b.searchData) === null || _c === void 0 ? void 0 : _c.posts) || [];
|
|
435
|
+
for (const p of posts) {
|
|
436
|
+
if (results.length >= max)
|
|
437
|
+
break;
|
|
438
|
+
const title = p.title || '';
|
|
439
|
+
const mid = p.mediumUrl || p.id ? `https://medium.com/p/${p.id}` : '';
|
|
440
|
+
results.push({ title, url: mid, snippet: (p.subtitle || ((_d = p.previewContent) === null || _d === void 0 ? void 0 : _d.subtitle) || '').substring(0, 300), source: 'medium', mediumAuthor: (_f = p.author) === null || _f === void 0 ? void 0 : _f.name, mediumClaps: p.clapCount });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (_e) { }
|
|
444
|
+
}
|
|
445
|
+
if (results.length === 0) {
|
|
446
|
+
const articleRx = /<article[^>]*>([\s\S]*?)<\/article>/gi;
|
|
447
|
+
let am;
|
|
448
|
+
while ((am = articleRx.exec(html)) !== null && results.length < max) {
|
|
449
|
+
const block = am[1];
|
|
450
|
+
const tm = block.match(/<h[23][^>]*>([\s\S]*?)<\/h[23]>/i);
|
|
451
|
+
const lm = block.match(/href="(https?:\/\/medium\.com\/[^"]+)"/i);
|
|
452
|
+
if ((tm === null || tm === void 0 ? void 0 : tm[1]) && (lm === null || lm === void 0 ? void 0 : lm[1])) {
|
|
453
|
+
results.push({ title: decodeEnt(stripHtml(tm[1])), url: lm[1], snippet: '', source: 'medium' });
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
catch (_e) { }
|
|
459
|
+
return results;
|
|
460
|
+
}
|
|
461
|
+
async function searchDevTo(ctx, query, max) {
|
|
462
|
+
var _a, _b;
|
|
463
|
+
const url = `https://dev.to/api/articles?per_page=${max}&tag=${encodeURIComponent(query)}`;
|
|
464
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url, { 'api-key': '' }), 1));
|
|
465
|
+
const results = [];
|
|
466
|
+
if (Array.isArray(data)) {
|
|
467
|
+
for (const a of data) {
|
|
468
|
+
if (results.length >= max)
|
|
469
|
+
break;
|
|
470
|
+
results.push({
|
|
471
|
+
title: a.title || '', url: a.url || a.canonical_url || '',
|
|
472
|
+
snippet: ((_a = a.description) === null || _a === void 0 ? void 0 : _a.substring(0, 300)) || '', source: 'devto',
|
|
473
|
+
devtoAuthor: (_b = a.user) === null || _b === void 0 ? void 0 : _b.name, devtoLikes: a.positive_reactions_count,
|
|
474
|
+
devtoComments: a.comments_count, devtoTags: a.tag_list,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return results;
|
|
479
|
+
}
|
|
480
|
+
async function searchProductHunt(ctx, query, max) {
|
|
481
|
+
var _a, _b, _c;
|
|
482
|
+
const results = [];
|
|
483
|
+
try {
|
|
484
|
+
const gqlBody = JSON.stringify({
|
|
485
|
+
query: `{ posts(order: VOTED, first: ${max}, search: "${query.replace(/"/g, '\\"')}") { edges { node { id name tagline url votesCount website createdAt topics { edges { node { name } } } } } } }`,
|
|
486
|
+
});
|
|
487
|
+
const data = (await retryRequest(ctx, {
|
|
488
|
+
method: 'POST',
|
|
489
|
+
url: 'https://www.producthunt.com/frontend/graphql',
|
|
490
|
+
headers: { 'User-Agent': randomUa(), 'Content-Type': 'application/json', Accept: 'application/json', Origin: 'https://www.producthunt.com', Referer: 'https://www.producthunt.com/' },
|
|
491
|
+
body: gqlBody, timeout: 15000, returnFullResponse: false, json: true,
|
|
492
|
+
}, 1));
|
|
493
|
+
const edges = (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.posts) === null || _b === void 0 ? void 0 : _b.edges) !== null && _c !== void 0 ? _c : [];
|
|
494
|
+
for (const e of edges) {
|
|
495
|
+
if (results.length >= max)
|
|
496
|
+
break;
|
|
497
|
+
const n = e.node;
|
|
498
|
+
results.push({
|
|
499
|
+
title: n.name || '', url: n.website || n.url || '',
|
|
500
|
+
snippet: n.tagline || '', source: 'producthunt',
|
|
501
|
+
phVotes: n.votesCount, phCreatedAt: n.createdAt,
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
catch (_e) {
|
|
506
|
+
try {
|
|
507
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(`https://www.producthunt.com/search?q=${encodeURIComponent(query)}`), 1));
|
|
508
|
+
const itemRx = /<h[23][^>]*>([\s\S]*?)<\/h[23]>/gi;
|
|
509
|
+
const linkRx = /href="(https?:\/\/www\.producthunt\.com\/posts\/[^"]+)"/gi;
|
|
510
|
+
const titles = [];
|
|
511
|
+
let tm;
|
|
512
|
+
while ((tm = itemRx.exec(html)) !== null)
|
|
513
|
+
titles.push(stripHtml(tm[1]));
|
|
514
|
+
let lm;
|
|
515
|
+
let idx = 0;
|
|
516
|
+
while ((lm = linkRx.exec(html)) !== null && results.length < max) {
|
|
517
|
+
results.push({ title: titles[idx] || 'Product Hunt Post', url: lm[1], snippet: '', source: 'producthunt' });
|
|
518
|
+
idx++;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch (_e2) { }
|
|
522
|
+
}
|
|
523
|
+
return results;
|
|
524
|
+
}
|
|
525
|
+
async function searchArXiv(ctx, query, max) {
|
|
526
|
+
const url = `https://export.arxiv.org/api/query?search_query=all:${encodeURIComponent(query)}&max_results=${max}&start=0`;
|
|
527
|
+
const xml = (await retryRequest(ctx, { ...jsonRequestOpts(url), json: false, headers: { Accept: 'application/xml, text/xml' } }));
|
|
528
|
+
const results = [];
|
|
529
|
+
const entryRx = /<entry>([\s\S]*?)<\/entry>/gi;
|
|
530
|
+
let em;
|
|
531
|
+
while ((em = entryRx.exec(xml)) !== null && results.length < max) {
|
|
532
|
+
const e = em[1];
|
|
533
|
+
const tm = e.match(/<title>([\s\S]*?)<\/title>/i);
|
|
534
|
+
const lm = e.match(/<id>([\s\S]*?)<\/id>/i);
|
|
535
|
+
const sm = e.match(/<summary>([\s\S]*?)<\/summary>/i);
|
|
536
|
+
const am = e.match(/<author>[\s\S]*?<name>([\s\S]*?)<\/name>[\s\S]*?<\/author>/i);
|
|
537
|
+
const cm = e.match(/<published>([\s\S]*?)<\/published>/i);
|
|
538
|
+
if ((tm === null || tm === void 0 ? void 0 : tm[1]) && (lm === null || lm === void 0 ? void 0 : lm[1])) {
|
|
539
|
+
results.push({
|
|
540
|
+
title: stripHtml(tm[1]), url: lm[1],
|
|
541
|
+
snippet: sm ? stripHtml(sm[1]).substring(0, 400) : '', source: 'arxiv',
|
|
542
|
+
arxivAuthor: am ? stripHtml(am[1]) : undefined, arxivPublished: cm ? cm[1].trim() : undefined,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return results;
|
|
547
|
+
}
|
|
548
|
+
async function searchPinterest(ctx, query, max) {
|
|
549
|
+
var _a, _b, _c, _d, _f;
|
|
550
|
+
const results = [];
|
|
551
|
+
try {
|
|
552
|
+
const url = `https://www.pinterest.com/search/pins/?q=${encodeURIComponent(query)}`;
|
|
553
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, { Accept: 'text/html', Referer: 'https://www.pinterest.com/' }), 2));
|
|
554
|
+
const dataMatch = html.match(/<script[^>]*id="__PWS_DATA__"[^>]*>([\s\S]*?)<\/script>/i);
|
|
555
|
+
if (dataMatch) {
|
|
556
|
+
try {
|
|
557
|
+
const pd = JSON.parse(dataMatch[1]);
|
|
558
|
+
const pins = ((_b = (_a = pd === null || pd === void 0 ? void 0 : pd.props) === null || _a === void 0 ? void 0 : _a.initialReduxState) === null || _b === void 0 ? void 0 : _b.pins) || {};
|
|
559
|
+
let count = 0;
|
|
560
|
+
for (const pinId of Object.keys(pins)) {
|
|
561
|
+
if (count >= max)
|
|
562
|
+
break;
|
|
563
|
+
const pin = pins[pinId];
|
|
564
|
+
if ((_d = (_c = pin === null || pin === void 0 ? void 0 : pin.images) === null || _c === void 0 ? void 0 : _c.orig) === null || _d === void 0 ? void 0 : _d.url) {
|
|
565
|
+
results.push({
|
|
566
|
+
title: (pin.title || pin.grid_title || `Pin by ${((_f = pin.board_owner) === null || _f === void 0 ? void 0 : _f.username) || 'unknown'}`),
|
|
567
|
+
url: `https://www.pinterest.com/pin/${pinId}/`,
|
|
568
|
+
snippet: (pin.description || '').substring(0, 300),
|
|
569
|
+
source: 'pinterest', pinterestImage: pin.images.orig.url,
|
|
570
|
+
pinterestSaves: pin.save_count,
|
|
571
|
+
});
|
|
572
|
+
count++;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
catch (_e) { }
|
|
577
|
+
}
|
|
578
|
+
if (results.length === 0) {
|
|
579
|
+
const pinRx = /<div[^>]*data-pin-id="(\d+)"[^>]*>([\s\S]*?)<\/div>/gi;
|
|
580
|
+
const descRx = /<div[^>]*class="[^"]*pinDescription[^"]*"[^>]*>([\s\S]*?)<\/div>/gi;
|
|
581
|
+
const descriptions = [];
|
|
582
|
+
let dm;
|
|
583
|
+
while ((dm = descRx.exec(html)) !== null)
|
|
584
|
+
descriptions.push(stripHtml(dm[1]));
|
|
585
|
+
let pm;
|
|
586
|
+
let idx = 0;
|
|
587
|
+
while ((pm = pinRx.exec(html)) !== null && results.length < max) {
|
|
588
|
+
results.push({ title: `Pinterest Pin`, url: `https://www.pinterest.com/pin/${pm[1]}/`, snippet: descriptions[idx] || '', source: 'pinterest' });
|
|
589
|
+
idx++;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
catch (_e) { }
|
|
594
|
+
return results;
|
|
595
|
+
}
|
|
596
|
+
async function searchFacebook(ctx, query, max) {
|
|
597
|
+
var _a, _b;
|
|
598
|
+
const results = [];
|
|
599
|
+
try {
|
|
600
|
+
const url = `https://m.facebook.com/public/search/?query=${encodeURIComponent(query)}&view=public`;
|
|
601
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, {
|
|
602
|
+
Accept: 'text/html', 'Accept-Language': 'en-US,en;q=0.9',
|
|
603
|
+
'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate',
|
|
604
|
+
}), 1));
|
|
605
|
+
const linkRx = /href="(\/(?!\/)[^"]*)"/gi;
|
|
606
|
+
const titleRx = /<span[^>]*>([^<]{20,})<\/span>/gi;
|
|
607
|
+
const titles = [];
|
|
608
|
+
let tm;
|
|
609
|
+
while ((tm = titleRx.exec(html)) !== null && titles.length < max * 3) {
|
|
610
|
+
const t = stripHtml(tm[1]).trim();
|
|
611
|
+
if (t.length > 15 && !t.includes('Facebook') && !t.includes('Log In'))
|
|
612
|
+
titles.push(t);
|
|
613
|
+
}
|
|
614
|
+
const seen = new Set();
|
|
615
|
+
let lm;
|
|
616
|
+
let idx = 0;
|
|
617
|
+
while ((lm = linkRx.exec(html)) !== null && results.length < max) {
|
|
618
|
+
const path = lm[1];
|
|
619
|
+
if (path.includes('story_fbid') || path.includes('/posts/') || path.includes('/groups/')) {
|
|
620
|
+
const fullUrl = `https://www.facebook.com${path}`;
|
|
621
|
+
if (!seen.has(fullUrl)) {
|
|
622
|
+
seen.add(fullUrl);
|
|
623
|
+
results.push({ title: titles[idx] || 'Facebook Post', url: fullUrl, snippet: '', source: 'facebook' });
|
|
624
|
+
idx++;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
catch (_e) { }
|
|
630
|
+
if (results.length === 0) {
|
|
631
|
+
try {
|
|
632
|
+
const url = `https://graph.facebook.com/v19.0/pages/search?q=${encodeURIComponent(query)}&limit=${max}&fields=id,name,description,link,website`;
|
|
633
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url), 1));
|
|
634
|
+
for (const p of ((_a = data.data) !== null && _a !== void 0 ? _a : [])) {
|
|
635
|
+
if (results.length >= max)
|
|
636
|
+
break;
|
|
637
|
+
results.push({
|
|
638
|
+
title: p.name || '', url: p.link || p.website || '',
|
|
639
|
+
snippet: ((_b = p.description) === null || _b === void 0 ? void 0 : _b.substring(0, 300)) || '', source: 'facebook',
|
|
640
|
+
facebookId: p.id,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
catch (_e) { }
|
|
645
|
+
}
|
|
646
|
+
return results;
|
|
647
|
+
}
|
|
648
|
+
async function searchLinkedIn(ctx, query, max, searchType) {
|
|
649
|
+
const results = [];
|
|
650
|
+
try {
|
|
651
|
+
const path = searchType === 'jobs' ? 'jobs/search' : 'search/results/people';
|
|
652
|
+
const url = `https://www.linkedin.com/${path}?keywords=${encodeURIComponent(query)}&origin=GLOBAL_SEARCH_HEADER`;
|
|
653
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, {
|
|
654
|
+
Accept: 'text/html', 'Accept-Language': 'en-US,en;q=0.9',
|
|
655
|
+
'Sec-Fetch-Dest': 'document',
|
|
656
|
+
}), 2));
|
|
657
|
+
const nameRx = /<span[^>]*class="[^"]*entity-result__title[^"]*"[^>]*>([\s\S]*?)<\/span>/i;
|
|
658
|
+
const linkRx = /href="(https?:\/\/www\.linkedin\.com\/in\/[^"]+)"/gi;
|
|
659
|
+
const subtitleRx = /<span[^>]*class="[^"]*entity-result__primary-subtitle[^"]*"[^>]*>([\s\S]*?)<\/span>/i;
|
|
660
|
+
const names = [];
|
|
661
|
+
const subtitles = [];
|
|
662
|
+
let nm;
|
|
663
|
+
while ((nm = nameRx.exec(html)) !== null)
|
|
664
|
+
names.push(stripHtml(nm[1]));
|
|
665
|
+
let sm;
|
|
666
|
+
while ((sm = subtitleRx.exec(html)) !== null)
|
|
667
|
+
subtitles.push(stripHtml(sm[1]));
|
|
668
|
+
const links = [];
|
|
669
|
+
let lm;
|
|
670
|
+
while ((lm = linkRx.exec(html)) !== null)
|
|
671
|
+
links.push(lm[1]);
|
|
672
|
+
for (let i = 0; i < Math.min(names.length, links.length, max); i++) {
|
|
673
|
+
results.push({
|
|
674
|
+
title: names[i] || 'LinkedIn Profile',
|
|
675
|
+
url: links[i],
|
|
676
|
+
snippet: subtitles[i] || '', source: 'linkedin',
|
|
677
|
+
linkedinSubtitle: subtitles[i] || undefined,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
catch (_e) { }
|
|
682
|
+
return results;
|
|
683
|
+
}
|
|
684
|
+
async function searchTelegram(ctx, query, max) {
|
|
685
|
+
const results = [];
|
|
686
|
+
try {
|
|
687
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query + ' site:t.me')}`;
|
|
688
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url), 1));
|
|
689
|
+
const blocks = html.split('class="result__body"');
|
|
690
|
+
for (let i = 1; i < blocks.length && results.length < max; i++) {
|
|
691
|
+
const b = blocks[i];
|
|
692
|
+
const tm = b.match(/class="result__a"[^>]*>([\s\S]*?)<\/a>/);
|
|
693
|
+
const hm = b.match(/href="(https?:\/\/t\.me\/[^"]+)"/);
|
|
694
|
+
const sm = b.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
|
|
695
|
+
if (tm && hm) {
|
|
696
|
+
const title = decodeEnt(stripHtml(tm[1]));
|
|
697
|
+
if (title.toLowerCase().includes(query.toLowerCase().split(' ')[0])) {
|
|
698
|
+
results.push({ title, url: hm[1], snippet: sm ? decodeEnt(stripHtml(sm[1])) : '', source: 'telegram' });
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
catch (_e) { }
|
|
704
|
+
if (results.length < max) {
|
|
705
|
+
try {
|
|
706
|
+
const rssUrl = `https://rsshub.app/telegram/channel/${encodeURIComponent(query.toLowerCase().replace(/\s+/g, ''))}`;
|
|
707
|
+
const xml = (await retryRequest(ctx, { ...jsonRequestOpts(rssUrl), json: false, headers: { Accept: 'application/rss+xml' } }, 1));
|
|
708
|
+
const itemRx = /<item>([\s\S]*?)<\/item>/gi;
|
|
709
|
+
let im;
|
|
710
|
+
while ((im = itemRx.exec(xml)) !== null && results.length < max) {
|
|
711
|
+
const ix = im[1];
|
|
712
|
+
const tm = ix.match(/<title>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/title>/i);
|
|
713
|
+
const lm = ix.match(/<link>(?:<!\[CDATA\[)?([\s\S]*?)(?:\]\]>)?<\/link>/i);
|
|
714
|
+
if ((tm === null || tm === void 0 ? void 0 : tm[1]) && (lm === null || lm === void 0 ? void 0 : lm[1])) {
|
|
715
|
+
results.push({ title: decodeEnt(stripHtml(tm[1])), url: decodeEnt(stripHtml(lm[1])), snippet: '', source: 'telegram' });
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
catch (_e) { }
|
|
720
|
+
}
|
|
721
|
+
return results;
|
|
722
|
+
}
|
|
723
|
+
async function searchRedditSubreddit(ctx, subreddit, max, sort, time) {
|
|
724
|
+
var _a, _b;
|
|
725
|
+
const url = `https://www.reddit.com/r/${subreddit}/${sort}.json?limit=${max}&t=${time}`;
|
|
726
|
+
const data = (await retryRequest(ctx, jsonRequestOpts(url)));
|
|
727
|
+
const results = [];
|
|
728
|
+
for (const c of ((_b = (_a = data.data) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [])) {
|
|
729
|
+
if (results.length >= max)
|
|
730
|
+
break;
|
|
731
|
+
const p = c.data;
|
|
732
|
+
if (!p || p.over_18)
|
|
733
|
+
continue;
|
|
734
|
+
results.push({
|
|
735
|
+
title: p.title || '', url: `https://reddit.com${p.permalink}`,
|
|
736
|
+
snippet: p.selftext ? stripHtml(p.selftext).substring(0, 500) : '',
|
|
737
|
+
source: 'reddit-subreddit', redditScore: p.score,
|
|
738
|
+
redditAuthor: p.author, redditSubreddit: p.subreddit,
|
|
739
|
+
redditNumComments: p.num_comments,
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
return results;
|
|
743
|
+
}
|
|
744
|
+
async function searchInstagram(ctx, query, max) {
|
|
745
|
+
const results = [];
|
|
746
|
+
try {
|
|
747
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query + ' site:instagram.com')}`;
|
|
748
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url), 1));
|
|
749
|
+
const blocks = html.split('class="result__body"');
|
|
750
|
+
for (let i = 1; i < blocks.length && results.length < max; i++) {
|
|
751
|
+
const b = blocks[i];
|
|
752
|
+
const tm = b.match(/class="result__a"[^>]*>([\s\S]*?)<\/a>/);
|
|
753
|
+
const hm = b.match(/href="(https?:\/\/www\.instagram\.com\/(?!about|explore|accounts|legal|help|api|developer)[^"]+)"/);
|
|
754
|
+
const sm = b.match(/class="result__snippet"[^>]*>([\s\S]*?)<\/a>/);
|
|
755
|
+
if (tm && hm) {
|
|
756
|
+
results.push({
|
|
757
|
+
title: decodeEnt(stripHtml(tm[1])), url: hm[1],
|
|
758
|
+
snippet: sm ? decodeEnt(stripHtml(sm[1])) : '', source: 'instagram',
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch (_e) { }
|
|
764
|
+
return results;
|
|
765
|
+
}
|
|
766
|
+
async function searchTikTok(ctx, query, max) {
|
|
767
|
+
var _a, _b;
|
|
768
|
+
const results = [];
|
|
769
|
+
try {
|
|
770
|
+
const url = `https://www.tiktok.com/search?q=${encodeURIComponent(query)}`;
|
|
771
|
+
const html = (await retryRequest(ctx, htmlRequestOpts(url, {
|
|
772
|
+
Accept: 'text/html', 'Accept-Language': 'en-US,en;q=0.9',
|
|
773
|
+
'Sec-Fetch-Dest': 'document',
|
|
774
|
+
}), 1));
|
|
775
|
+
const sigiMatch = html.match(/<script[^>]*id="SIGI_STATE"[^>]*>([\s\S]*?)<\/script>/i);
|
|
776
|
+
if (sigiMatch) {
|
|
777
|
+
try {
|
|
778
|
+
const sd = JSON.parse(sigiMatch[1]);
|
|
779
|
+
const itemModule = (sd === null || sd === void 0 ? void 0 : sd.ItemModule) || {};
|
|
780
|
+
let count = 0;
|
|
781
|
+
for (const itemId of Object.keys(itemModule)) {
|
|
782
|
+
if (count >= max)
|
|
783
|
+
break;
|
|
784
|
+
const item = itemModule[itemId];
|
|
785
|
+
results.push({
|
|
786
|
+
title: ((_a = item.desc) === null || _a === void 0 ? void 0 : _a.substring(0, 100)) || 'TikTok Video',
|
|
787
|
+
url: `https://www.tiktok.com/@${item.author || 'user'}/video/${itemId}`,
|
|
788
|
+
snippet: ((_b = item.desc) === null || _b === void 0 ? void 0 : _b.substring(0, 300)) || '', source: 'tiktok',
|
|
789
|
+
tiktokAuthor: item.author,
|
|
790
|
+
tiktokPlays: item.playCount,
|
|
791
|
+
tiktokLikes: item.diggCount,
|
|
792
|
+
});
|
|
793
|
+
count++;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
catch (_e) { }
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
catch (_e) { }
|
|
800
|
+
return results;
|
|
801
|
+
}
|
|
802
|
+
async function deepResearch(ctx, query, max) {
|
|
803
|
+
const allResults = [];
|
|
804
|
+
const perSource = Math.max(2, Math.ceil(max / 10));
|
|
805
|
+
const settled = await Promise.allSettled([
|
|
806
|
+
searchDuckDuckGo(ctx, query, perSource),
|
|
807
|
+
searchReddit(ctx, query, perSource, 'relevance', 'all'),
|
|
808
|
+
searchHackerNews(ctx, query, perSource, false, 'story'),
|
|
809
|
+
searchWikipedia(ctx, query, perSource, 'en', true),
|
|
810
|
+
searchNewsRSS(ctx, query, perSource, 'google'),
|
|
811
|
+
searchGitHub(ctx, query, perSource, 'repositories', ''),
|
|
812
|
+
searchStackExchange(ctx, query, perSource, 'stackoverflow'),
|
|
813
|
+
searchDevTo(ctx, query, perSource),
|
|
814
|
+
searchTwitter(ctx, query, perSource),
|
|
815
|
+
searchYouTube(ctx, query, perSource),
|
|
816
|
+
searchQuora(ctx, query, perSource),
|
|
817
|
+
searchMedium(ctx, query, perSource),
|
|
818
|
+
searchProductHunt(ctx, query, perSource),
|
|
819
|
+
searchArXiv(ctx, query, perSource),
|
|
820
|
+
searchPinterest(ctx, query, perSource),
|
|
821
|
+
searchTelegram(ctx, query, perSource),
|
|
822
|
+
]);
|
|
823
|
+
for (const r of settled) {
|
|
824
|
+
if (r.status === 'fulfilled')
|
|
825
|
+
allResults.push(...r.value);
|
|
826
|
+
}
|
|
827
|
+
return allResults.slice(0, max);
|
|
828
|
+
}
|
|
829
|
+
class DeepResearch {
|
|
830
|
+
constructor() {
|
|
831
|
+
this.description = {
|
|
832
|
+
displayName: 'Deep Research',
|
|
833
|
+
name: 'deepResearch',
|
|
834
|
+
icon: { light: 'file:DeepResearch.svg', dark: 'file:DeepResearch.dark.svg' },
|
|
835
|
+
group: ['transform'],
|
|
836
|
+
version: 1,
|
|
837
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
838
|
+
description: 'Research anything online for free \u2014 22+ sources including Reddit, X/Twitter, Facebook, YouTube, Hacker News, Wikipedia, Quora, Medium, LinkedIn, TikTok, Instagram, GitHub, and more. Zero API keys needed. Built-in anti-IP-blocking.',
|
|
839
|
+
defaults: { name: 'Deep Research' },
|
|
840
|
+
inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
841
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
842
|
+
usableAsTool: true,
|
|
843
|
+
properties: [
|
|
844
|
+
{
|
|
845
|
+
displayName: 'Operation',
|
|
846
|
+
name: 'operation',
|
|
847
|
+
type: 'options',
|
|
848
|
+
noDataExpression: true,
|
|
849
|
+
options: [
|
|
850
|
+
{ name: 'Web Search', value: 'webSearch', description: 'DuckDuckGo search' },
|
|
851
|
+
{ name: 'Reddit Search', value: 'redditSearch', description: 'Search all of Reddit' },
|
|
852
|
+
{ name: 'Reddit Subreddit', value: 'redditSubreddit', description: 'Browse a specific subreddit' },
|
|
853
|
+
{ name: 'X / Twitter', value: 'twitter', description: 'Search tweets (via fxtwitter/Nitter)' },
|
|
854
|
+
{ name: 'Facebook', value: 'facebook', description: 'Search public pages/groups' },
|
|
855
|
+
{ name: 'YouTube', value: 'youtube', description: 'Search videos via Invidious' },
|
|
856
|
+
{ name: 'Hacker News', value: 'hackerNews', description: 'HN stories/comments' },
|
|
857
|
+
{ name: 'Wikipedia', value: 'wikipedia', description: 'Wikipedia articles' },
|
|
858
|
+
{ name: 'News / RSS', value: 'newsRss', description: 'Google News, BBC, TechCrunch, Reuters, custom RSS' },
|
|
859
|
+
{ name: 'GitHub', value: 'github', description: 'Repos, issues, code, users' },
|
|
860
|
+
{ name: 'Stack Exchange', value: 'stackExchange', description: 'StackOverflow, SuperUser, etc.' },
|
|
861
|
+
{ name: 'Quora', value: 'quora', description: 'Search Quora questions' },
|
|
862
|
+
{ name: 'Medium', value: 'medium', description: 'Search Medium articles' },
|
|
863
|
+
{ name: 'Dev.to', value: 'devto', description: 'Search Dev.to articles' },
|
|
864
|
+
{ name: 'Product Hunt', value: 'producthunt', description: 'Search Product Hunt' },
|
|
865
|
+
{ name: 'ArXiv Papers', value: 'arxiv', description: 'Search academic papers' },
|
|
866
|
+
{ name: 'Pinterest', value: 'pinterest', description: 'Search pins' },
|
|
867
|
+
{ name: 'LinkedIn', value: 'linkedin', description: 'Search people or jobs' },
|
|
868
|
+
{ name: 'Telegram', value: 'telegram', description: 'Find Telegram channels/groups' },
|
|
869
|
+
{ name: 'Instagram', value: 'instagram', description: 'Find public Instagram posts' },
|
|
870
|
+
{ name: 'TikTok', value: 'tiktok', description: 'Search TikTok videos' },
|
|
871
|
+
{ name: 'Scrape Web Page', value: 'scrape', description: 'Fetch any URL content' },
|
|
872
|
+
{ name: 'Deep Research (ALL)', value: 'deepResearch', description: 'Aggregate from all 16+ sources in parallel' },
|
|
873
|
+
],
|
|
874
|
+
default: 'webSearch',
|
|
875
|
+
},
|
|
876
|
+
{
|
|
877
|
+
displayName: 'Search Query',
|
|
878
|
+
name: 'query',
|
|
879
|
+
type: 'string',
|
|
880
|
+
required: true,
|
|
881
|
+
default: '',
|
|
882
|
+
placeholder: 'e.g. best mechanical keyboards 2025',
|
|
883
|
+
description: 'What to search for',
|
|
884
|
+
displayOptions: { hide: { operation: ['scrape', 'redditSubreddit'] } },
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
displayName: 'Max Results',
|
|
888
|
+
name: 'maxResults',
|
|
889
|
+
type: 'number',
|
|
890
|
+
default: 10,
|
|
891
|
+
description: 'Max results to return (1-100)',
|
|
892
|
+
displayOptions: { hide: { operation: ['scrape', 'redditSubreddit'] } },
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
displayName: 'Sort By', name: 'redditSort', type: 'options', default: 'relevance',
|
|
896
|
+
options: [{ name: 'Relevance', value: 'relevance' }, { name: 'Hot', value: 'hot' }, { name: 'Top', value: 'top' }, { name: 'New', value: 'new' }, { name: 'Comments', value: 'comments' }],
|
|
897
|
+
description: 'Sort Reddit results', displayOptions: { show: { operation: ['redditSearch'] } },
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
displayName: 'Time Filter', name: 'redditTimeFilter', type: 'options', default: 'all',
|
|
901
|
+
options: [{ name: 'All Time', value: 'all' }, { name: 'Past Hour', value: 'hour' }, { name: 'Past Day', value: 'day' }, { name: 'Past Week', value: 'week' }, { name: 'Past Month', value: 'month' }, { name: 'Past Year', value: 'year' }],
|
|
902
|
+
description: 'Reddit time range', displayOptions: { show: { operation: ['redditSearch'] } },
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
displayName: 'Subreddit Name', name: 'subredditName', type: 'string', required: true, default: '',
|
|
906
|
+
placeholder: 'e.g. programming', description: 'Name of the subreddit (without r/)',
|
|
907
|
+
displayOptions: { show: { operation: ['redditSubreddit'] } },
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
displayName: 'Sort By', name: 'subredditSort', type: 'options', default: 'hot',
|
|
911
|
+
options: [{ name: 'Hot', value: 'hot' }, { name: 'New', value: 'new' }, { name: 'Top', value: 'top' }, { name: 'Rising', value: 'rising' }, { name: 'Controversial', value: 'controversial' }],
|
|
912
|
+
displayOptions: { show: { operation: ['redditSubreddit'] } },
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
displayName: 'Time Filter', name: 'subredditTime', type: 'options', default: 'all',
|
|
916
|
+
options: [{ name: 'All Time', value: 'all' }, { name: 'Past Day', value: 'day' }, { name: 'Past Week', value: 'week' }, { name: 'Past Month', value: 'month' }, { name: 'Past Year', value: 'year' }],
|
|
917
|
+
displayOptions: { show: { operation: ['redditSubreddit'] } },
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
displayName: 'Sort By', name: 'hnSort', type: 'options', default: 'popularity',
|
|
921
|
+
options: [{ name: 'Popularity', value: 'popularity' }, { name: 'Date', value: 'date' }],
|
|
922
|
+
displayOptions: { show: { operation: ['hackerNews'] } },
|
|
923
|
+
},
|
|
924
|
+
{
|
|
925
|
+
displayName: 'Content Type', name: 'hnTags', type: 'options', default: 'story',
|
|
926
|
+
options: [{ name: 'Stories', value: 'story' }, { name: 'Comments', value: 'comment' }, { name: 'All', value: '(story,comment)' }, { name: 'Ask HN', value: 'ask_hn' }, { name: 'Show HN', value: 'show_hn' }],
|
|
927
|
+
displayOptions: { show: { operation: ['hackerNews'] } },
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
displayName: 'Language', name: 'wikiLanguage', type: 'string', default: 'en',
|
|
931
|
+
description: 'Wikipedia language code (en, de, fr, es, ja, ...)',
|
|
932
|
+
displayOptions: { show: { operation: ['wikipedia'] } },
|
|
933
|
+
},
|
|
934
|
+
{
|
|
935
|
+
displayName: 'Fetch Full Extracts', name: 'wikiExtracts', type: 'boolean', default: true,
|
|
936
|
+
description: 'Get first sentences of each article', displayOptions: { show: { operation: ['wikipedia'] } },
|
|
937
|
+
},
|
|
938
|
+
{
|
|
939
|
+
displayName: 'News Source', name: 'newsSource', type: 'options', default: 'google',
|
|
940
|
+
options: [{ name: 'Google News', value: 'google' }, { name: 'BBC News', value: 'bbc' }, { name: 'TechCrunch', value: 'techcrunch' }, { name: 'Reuters', value: 'reuters' }, { name: 'Custom RSS Feed URL', value: 'custom' }],
|
|
941
|
+
displayOptions: { show: { operation: ['newsRss'] } },
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
displayName: 'Custom RSS Feed URL', name: 'customRssUrl', type: 'string', default: '',
|
|
945
|
+
placeholder: 'https://example.com/feed.xml',
|
|
946
|
+
displayOptions: { show: { operation: ['newsRss'], newsSource: ['custom'] } },
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
displayName: 'Search Type', name: 'githubSearchType', type: 'options', default: 'repositories',
|
|
950
|
+
options: [{ name: 'Repositories', value: 'repositories' }, { name: 'Issues', value: 'issues' }, { name: 'Code', value: 'code' }, { name: 'Users', value: 'users' }],
|
|
951
|
+
displayOptions: { show: { operation: ['github'] } },
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
displayName: 'Sort By', name: 'githubSort', type: 'options', default: 'best match',
|
|
955
|
+
options: [{ name: 'Best Match', value: '' }, { name: 'Stars', value: 'stars' }, { name: 'Forks', value: 'forks' }, { name: 'Updated', value: 'updated' }],
|
|
956
|
+
displayOptions: { show: { operation: ['github'] } },
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
displayName: 'Site', name: 'seSite', type: 'options', default: 'stackoverflow',
|
|
960
|
+
options: [{ name: 'StackOverflow', value: 'stackoverflow' }, { name: 'SuperUser', value: 'superuser' }, { name: 'ServerFault', value: 'serverfault' }, { name: 'AskUbuntu', value: 'askubuntu' }, { name: 'Math', value: 'math' }, { name: 'Physics', value: 'physics' }, { name: 'English', value: 'english' }],
|
|
961
|
+
displayOptions: { show: { operation: ['stackExchange'] } },
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
displayName: 'Search Type', name: 'linkedinType', type: 'options', default: 'people',
|
|
965
|
+
options: [{ name: 'People', value: 'people' }, { name: 'Jobs', value: 'jobs' }],
|
|
966
|
+
displayOptions: { show: { operation: ['linkedin'] } },
|
|
967
|
+
},
|
|
968
|
+
{
|
|
969
|
+
displayName: 'URL to Scrape', name: 'scrapeUrl', type: 'string', required: true, default: '',
|
|
970
|
+
placeholder: 'https://example.com/article',
|
|
971
|
+
displayOptions: { show: { operation: ['scrape'] } },
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
displayName: 'Extract Links', name: 'extractLinks', type: 'boolean', default: false,
|
|
975
|
+
description: 'Extract all hyperlinks from the page',
|
|
976
|
+
displayOptions: { show: { operation: ['scrape'] } },
|
|
977
|
+
},
|
|
978
|
+
{
|
|
979
|
+
displayName: 'Max Text Length', name: 'maxTextLength', type: 'number', default: 10000,
|
|
980
|
+
description: 'Max characters of text (500-100000)',
|
|
981
|
+
displayOptions: { show: { operation: ['scrape'] } },
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add field', default: {},
|
|
985
|
+
options: [
|
|
986
|
+
{ displayName: 'Return as Single Item', name: 'returnAsSingle', type: 'boolean', default: false, description: 'Return all results as one item with a "results" array' },
|
|
987
|
+
],
|
|
988
|
+
},
|
|
989
|
+
],
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
async execute() {
|
|
993
|
+
const op = this.getNodeParameter('operation', 0);
|
|
994
|
+
try {
|
|
995
|
+
const items = [];
|
|
996
|
+
const q = this.getNodeParameter('query', 0);
|
|
997
|
+
const max = this.getNodeParameter('maxResults', 0);
|
|
998
|
+
switch (op) {
|
|
999
|
+
case 'webSearch': {
|
|
1000
|
+
for (const r of await searchDuckDuckGo(this, q, max))
|
|
1001
|
+
items.push({ json: r });
|
|
1002
|
+
break;
|
|
1003
|
+
}
|
|
1004
|
+
case 'redditSearch': {
|
|
1005
|
+
for (const r of await searchReddit(this, q, max, this.getNodeParameter('redditSort', 0), this.getNodeParameter('redditTimeFilter', 0)))
|
|
1006
|
+
items.push({ json: r });
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
case 'redditSubreddit': {
|
|
1010
|
+
for (const r of await searchRedditSubreddit(this, this.getNodeParameter('subredditName', 0), 20, this.getNodeParameter('subredditSort', 0), this.getNodeParameter('subredditTime', 0)))
|
|
1011
|
+
items.push({ json: r });
|
|
1012
|
+
break;
|
|
1013
|
+
}
|
|
1014
|
+
case 'twitter': {
|
|
1015
|
+
for (const r of await searchTwitter(this, q, max))
|
|
1016
|
+
items.push({ json: r });
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
case 'facebook': {
|
|
1020
|
+
for (const r of await searchFacebook(this, q, max))
|
|
1021
|
+
items.push({ json: r });
|
|
1022
|
+
break;
|
|
1023
|
+
}
|
|
1024
|
+
case 'youtube': {
|
|
1025
|
+
for (const r of await searchYouTube(this, q, max))
|
|
1026
|
+
items.push({ json: r });
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1029
|
+
case 'hackerNews': {
|
|
1030
|
+
for (const r of await searchHackerNews(this, q, max, this.getNodeParameter('hnSort', 0) === 'date', this.getNodeParameter('hnTags', 0)))
|
|
1031
|
+
items.push({ json: r });
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
1034
|
+
case 'wikipedia': {
|
|
1035
|
+
for (const r of await searchWikipedia(this, q, max, this.getNodeParameter('wikiLanguage', 0), this.getNodeParameter('wikiExtracts', 0)))
|
|
1036
|
+
items.push({ json: r });
|
|
1037
|
+
break;
|
|
1038
|
+
}
|
|
1039
|
+
case 'newsRss': {
|
|
1040
|
+
const ns = this.getNodeParameter('newsSource', 0);
|
|
1041
|
+
for (const r of await searchNewsRSS(this, ns === 'custom' ? this.getNodeParameter('customRssUrl', 0) : q, max, ns))
|
|
1042
|
+
items.push({ json: r });
|
|
1043
|
+
break;
|
|
1044
|
+
}
|
|
1045
|
+
case 'github': {
|
|
1046
|
+
for (const r of await searchGitHub(this, q, max, this.getNodeParameter('githubSearchType', 0), this.getNodeParameter('githubSort', 0)))
|
|
1047
|
+
items.push({ json: r });
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
case 'stackExchange': {
|
|
1051
|
+
for (const r of await searchStackExchange(this, q, max, this.getNodeParameter('seSite', 0)))
|
|
1052
|
+
items.push({ json: r });
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
case 'quora': {
|
|
1056
|
+
for (const r of await searchQuora(this, q, max))
|
|
1057
|
+
items.push({ json: r });
|
|
1058
|
+
break;
|
|
1059
|
+
}
|
|
1060
|
+
case 'medium': {
|
|
1061
|
+
for (const r of await searchMedium(this, q, max))
|
|
1062
|
+
items.push({ json: r });
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1065
|
+
case 'devto': {
|
|
1066
|
+
for (const r of await searchDevTo(this, q, max))
|
|
1067
|
+
items.push({ json: r });
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
case 'producthunt': {
|
|
1071
|
+
for (const r of await searchProductHunt(this, q, max))
|
|
1072
|
+
items.push({ json: r });
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
case 'arxiv': {
|
|
1076
|
+
for (const r of await searchArXiv(this, q, max))
|
|
1077
|
+
items.push({ json: r });
|
|
1078
|
+
break;
|
|
1079
|
+
}
|
|
1080
|
+
case 'pinterest': {
|
|
1081
|
+
for (const r of await searchPinterest(this, q, max))
|
|
1082
|
+
items.push({ json: r });
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1085
|
+
case 'linkedin': {
|
|
1086
|
+
for (const r of await searchLinkedIn(this, q, max, this.getNodeParameter('linkedinType', 0)))
|
|
1087
|
+
items.push({ json: r });
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
case 'telegram': {
|
|
1091
|
+
for (const r of await searchTelegram(this, q, max))
|
|
1092
|
+
items.push({ json: r });
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
case 'instagram': {
|
|
1096
|
+
for (const r of await searchInstagram(this, q, max))
|
|
1097
|
+
items.push({ json: r });
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
case 'tiktok': {
|
|
1101
|
+
for (const r of await searchTikTok(this, q, max))
|
|
1102
|
+
items.push({ json: r });
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
case 'scrape': {
|
|
1106
|
+
items.push({ json: await scrapeWebPage(this, this.getNodeParameter('scrapeUrl', 0), this.getNodeParameter('extractLinks', 0), this.getNodeParameter('maxTextLength', 0)) });
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
case 'deepResearch': {
|
|
1110
|
+
for (const r of await deepResearch(this, q, max))
|
|
1111
|
+
items.push({ json: r });
|
|
1112
|
+
break;
|
|
1113
|
+
}
|
|
1114
|
+
default: throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation: ${op}`);
|
|
1115
|
+
}
|
|
1116
|
+
if (this.getNodeParameter('additionalFields.returnAsSingle', 0, false)) {
|
|
1117
|
+
return [[{ json: { operation: op, totalResults: items.length, results: items.map((i) => i.json) } }]];
|
|
1118
|
+
}
|
|
1119
|
+
return [items];
|
|
1120
|
+
}
|
|
1121
|
+
catch (error) {
|
|
1122
|
+
if (this.continueOnFail()) {
|
|
1123
|
+
return [[{ json: { error: error.message, operation: op }, pairedItem: { item: 0 } }]];
|
|
1124
|
+
}
|
|
1125
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: 0 });
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
exports.DeepResearch = DeepResearch;
|
|
1130
|
+
//# sourceMappingURL=DeepResearch.node.js.map
|