brave-real-browser-mcp-server 2.9.9 → 2.9.10
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.
|
@@ -49,7 +49,7 @@ export async function handleBrowserClose() {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
// Workflow validation wrapper
|
|
52
|
-
async function withWorkflowValidation(toolName, args, operation) {
|
|
52
|
+
export async function withWorkflowValidation(toolName, args, operation) {
|
|
53
53
|
// Validate workflow state before execution
|
|
54
54
|
const validation = validateWorkflow(toolName, args);
|
|
55
55
|
// Defensive check: if validation is undefined or null, allow execution (test environment)
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
// Specialized Tools Handlers for Video Extraction, Links Finding, AJAX, and User Agent Tools
|
|
2
|
+
import { getBrowser, getPage } from '../browser-manager.js';
|
|
3
|
+
import { withWorkflowValidation } from './browser-handlers.js';
|
|
4
|
+
import { withErrorHandling } from '../system-utils.js';
|
|
5
|
+
// Links Finders Handler
|
|
6
|
+
export async function handleLinksFinders(args) {
|
|
7
|
+
return withWorkflowValidation('links_finders', args, async () => {
|
|
8
|
+
return withErrorHandling(async () => {
|
|
9
|
+
const browser = getBrowser();
|
|
10
|
+
const page = getPage();
|
|
11
|
+
if (!browser || !page) {
|
|
12
|
+
throw new Error('Browser not initialized. Call browser_init first.');
|
|
13
|
+
}
|
|
14
|
+
const { includeExternal = true, includeInternal = true, includeMediaLinks = true, includeEmailPhone = false, filterDomains = [] } = args;
|
|
15
|
+
const links = await page.evaluate((options) => {
|
|
16
|
+
const { includeExternal, includeInternal, includeMediaLinks, includeEmailPhone, filterDomains } = options;
|
|
17
|
+
const results = [];
|
|
18
|
+
const currentDomain = window.location.hostname;
|
|
19
|
+
// Find all anchor links
|
|
20
|
+
const anchors = document.querySelectorAll('a[href]');
|
|
21
|
+
anchors.forEach((anchor) => {
|
|
22
|
+
const href = anchor.href;
|
|
23
|
+
const isExternal = !href.includes(currentDomain);
|
|
24
|
+
if ((isExternal && includeExternal) || (!isExternal && includeInternal)) {
|
|
25
|
+
if (filterDomains.length === 0 || filterDomains.some((domain) => href.includes(domain))) {
|
|
26
|
+
results.push({
|
|
27
|
+
type: 'anchor',
|
|
28
|
+
url: href,
|
|
29
|
+
text: anchor.textContent?.trim() || '',
|
|
30
|
+
isExternal,
|
|
31
|
+
title: anchor.title || ''
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
// Find media links if requested
|
|
37
|
+
if (includeMediaLinks) {
|
|
38
|
+
const mediaElements = document.querySelectorAll('img[src], video[src], audio[src], source[src]');
|
|
39
|
+
mediaElements.forEach((element) => {
|
|
40
|
+
results.push({
|
|
41
|
+
type: 'media',
|
|
42
|
+
url: element.src,
|
|
43
|
+
mediaType: element.tagName.toLowerCase(),
|
|
44
|
+
alt: element.alt || '',
|
|
45
|
+
title: element.title || ''
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Find email and phone links if requested
|
|
50
|
+
if (includeEmailPhone) {
|
|
51
|
+
const emailPhoneLinks = document.querySelectorAll('a[href^="mailto:"], a[href^="tel:"]');
|
|
52
|
+
emailPhoneLinks.forEach((link) => {
|
|
53
|
+
results.push({
|
|
54
|
+
type: link.href.startsWith('mailto:') ? 'email' : 'phone',
|
|
55
|
+
url: link.href,
|
|
56
|
+
text: link.textContent?.trim() || ''
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return results;
|
|
61
|
+
}, { includeExternal, includeInternal, includeMediaLinks, includeEmailPhone, filterDomains });
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
links,
|
|
65
|
+
total: links.length,
|
|
66
|
+
message: `Found ${links.length} links on the page`
|
|
67
|
+
};
|
|
68
|
+
}, 'Failed to find links');
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Video Play Sources Finder Handler
|
|
72
|
+
export async function handleVideoPlaySourcesFinder(args) {
|
|
73
|
+
return withWorkflowValidation('video_play_sources_finder', args, async () => {
|
|
74
|
+
return withErrorHandling(async () => {
|
|
75
|
+
const browser = getBrowser();
|
|
76
|
+
const page = getPage();
|
|
77
|
+
if (!browser || !page) {
|
|
78
|
+
throw new Error('Browser not initialized. Call browser_init first.');
|
|
79
|
+
}
|
|
80
|
+
const { includeHLS = true, includeDASH = true, includeDirectMP4 = true, includeBlob = true, recordingDuration = 15000 } = args;
|
|
81
|
+
// Start network monitoring
|
|
82
|
+
const networkSources = [];
|
|
83
|
+
await page.setRequestInterception(true);
|
|
84
|
+
page.on('request', (request) => {
|
|
85
|
+
request.continue();
|
|
86
|
+
});
|
|
87
|
+
page.on('response', async (response) => {
|
|
88
|
+
try {
|
|
89
|
+
const url = response.url();
|
|
90
|
+
const contentType = response.headers()['content-type'] || '';
|
|
91
|
+
// Check for video sources
|
|
92
|
+
const isVideoSource = ((includeHLS && (url.includes('.m3u8') || contentType.includes('application/x-mpegURL'))) ||
|
|
93
|
+
(includeDASH && (url.includes('.mpd') || contentType.includes('application/dash+xml'))) ||
|
|
94
|
+
(includeDirectMP4 && (url.includes('.mp4') || contentType.includes('video/mp4'))) ||
|
|
95
|
+
(includeBlob && url.startsWith('blob:')));
|
|
96
|
+
if (isVideoSource) {
|
|
97
|
+
networkSources.push({
|
|
98
|
+
url,
|
|
99
|
+
type: url.includes('.m3u8') ? 'HLS' :
|
|
100
|
+
url.includes('.mpd') ? 'DASH' :
|
|
101
|
+
url.includes('.mp4') ? 'MP4' :
|
|
102
|
+
url.startsWith('blob:') ? 'BLOB' : 'UNKNOWN',
|
|
103
|
+
contentType,
|
|
104
|
+
size: response.headers()['content-length'] || 'unknown',
|
|
105
|
+
status: response.status()
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// Ignore response processing errors
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// Wait for network activity
|
|
114
|
+
await new Promise(resolve => setTimeout(resolve, recordingDuration));
|
|
115
|
+
await page.setRequestInterception(false);
|
|
116
|
+
// Also search DOM for video sources
|
|
117
|
+
const domSources = await page.evaluate((options) => {
|
|
118
|
+
const { includeHLS, includeDASH, includeDirectMP4, includeBlob } = options;
|
|
119
|
+
const sources = [];
|
|
120
|
+
// Video elements
|
|
121
|
+
const videos = document.querySelectorAll('video');
|
|
122
|
+
videos.forEach((video) => {
|
|
123
|
+
if (video.src)
|
|
124
|
+
sources.push({ url: video.src, type: 'VIDEO_TAG', source: 'dom' });
|
|
125
|
+
const sourceTags = video.querySelectorAll('source');
|
|
126
|
+
sourceTags.forEach((source) => {
|
|
127
|
+
if (source.src)
|
|
128
|
+
sources.push({ url: source.src, type: source.type || 'VIDEO_SOURCE', source: 'dom' });
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
// Search for sources in page text/scripts
|
|
132
|
+
const scripts = document.querySelectorAll('script');
|
|
133
|
+
scripts.forEach((script) => {
|
|
134
|
+
const content = script.textContent || '';
|
|
135
|
+
if (includeHLS) {
|
|
136
|
+
const hlsMatches = content.match(/https?:\/\/[^\s"']+\.m3u8[^\s"']*/g);
|
|
137
|
+
if (hlsMatches) {
|
|
138
|
+
hlsMatches.forEach(url => sources.push({ url, type: 'HLS', source: 'script' }));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (includeDASH) {
|
|
142
|
+
const dashMatches = content.match(/https?:\/\/[^\s"']+\.mpd[^\s"']*/g);
|
|
143
|
+
if (dashMatches) {
|
|
144
|
+
dashMatches.forEach(url => sources.push({ url, type: 'DASH', source: 'script' }));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (includeDirectMP4) {
|
|
148
|
+
const mp4Matches = content.match(/https?:\/\/[^\s"']+\.mp4[^\s"']*/g);
|
|
149
|
+
if (mp4Matches) {
|
|
150
|
+
mp4Matches.forEach(url => sources.push({ url, type: 'MP4', source: 'script' }));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
return sources;
|
|
155
|
+
}, { includeHLS, includeDASH, includeDirectMP4, includeBlob });
|
|
156
|
+
const allSources = [...networkSources, ...domSources];
|
|
157
|
+
const uniqueSources = allSources.filter((source, index, array) => array.findIndex(s => s.url === source.url) === index);
|
|
158
|
+
return {
|
|
159
|
+
success: true,
|
|
160
|
+
sources: uniqueSources,
|
|
161
|
+
networkSources: networkSources.length,
|
|
162
|
+
domSources: domSources.length,
|
|
163
|
+
total: uniqueSources.length,
|
|
164
|
+
message: `Found ${uniqueSources.length} video play sources`
|
|
165
|
+
};
|
|
166
|
+
}, 'Failed to find video play sources');
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// Video Player Hostars Sources Finder Handler
|
|
170
|
+
export async function handleVideoPlayerHostarsSourcesFinder(args) {
|
|
171
|
+
return withWorkflowValidation('video_player_hostars_sources_finder', args, async () => {
|
|
172
|
+
return withErrorHandling(async () => {
|
|
173
|
+
const browser = getBrowser();
|
|
174
|
+
const page = getPage();
|
|
175
|
+
if (!browser || !page) {
|
|
176
|
+
throw new Error('Browser not initialized. Call browser_init first.');
|
|
177
|
+
}
|
|
178
|
+
const { platforms = ['all'], extractEmbedCodes = true, extractAPIKeys = false } = args;
|
|
179
|
+
const hostingSources = await page.evaluate((options) => {
|
|
180
|
+
const { platforms, extractEmbedCodes, extractAPIKeys } = options;
|
|
181
|
+
const sources = [];
|
|
182
|
+
// Define hosting platform patterns
|
|
183
|
+
const hostingPatterns = {
|
|
184
|
+
youtube: [
|
|
185
|
+
/(?:youtube\.com|youtu\.be)/i,
|
|
186
|
+
/\/embed\/([a-zA-Z0-9_-]+)/,
|
|
187
|
+
/watch\?v=([a-zA-Z0-9_-]+)/
|
|
188
|
+
],
|
|
189
|
+
vimeo: [
|
|
190
|
+
/vimeo\.com/i,
|
|
191
|
+
/\/video\/(\d+)/,
|
|
192
|
+
/player\.vimeo\.com\/video\/(\d+)/
|
|
193
|
+
],
|
|
194
|
+
dailymotion: [
|
|
195
|
+
/dailymotion\.com/i,
|
|
196
|
+
/\/video\/([a-zA-Z0-9_-]+)/
|
|
197
|
+
],
|
|
198
|
+
twitch: [
|
|
199
|
+
/twitch\.tv/i,
|
|
200
|
+
/\/videos\/(\d+)/,
|
|
201
|
+
/\/embed\/([a-zA-Z0-9_-]+)/
|
|
202
|
+
],
|
|
203
|
+
facebook: [
|
|
204
|
+
/facebook\.com/i,
|
|
205
|
+
/\/watch/,
|
|
206
|
+
/\/videos/
|
|
207
|
+
],
|
|
208
|
+
instagram: [
|
|
209
|
+
/instagram\.com/i,
|
|
210
|
+
/\/p\/([a-zA-Z0-9_-]+)/
|
|
211
|
+
],
|
|
212
|
+
tiktok: [
|
|
213
|
+
/tiktok\.com/i,
|
|
214
|
+
/@[^\/]+\/video\/(\d+)/
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
// Search in iframes
|
|
218
|
+
const iframes = document.querySelectorAll('iframe');
|
|
219
|
+
iframes.forEach((iframe) => {
|
|
220
|
+
const src = iframe.src;
|
|
221
|
+
if (!src)
|
|
222
|
+
return;
|
|
223
|
+
for (const [platform, patterns] of Object.entries(hostingPatterns)) {
|
|
224
|
+
if (platforms.includes('all') || platforms.includes(platform)) {
|
|
225
|
+
if (patterns[0].test(src)) {
|
|
226
|
+
const videoId = src.match(patterns[1] || patterns[0]);
|
|
227
|
+
sources.push({
|
|
228
|
+
platform,
|
|
229
|
+
url: src,
|
|
230
|
+
videoId: videoId ? videoId[1] : null,
|
|
231
|
+
type: 'iframe',
|
|
232
|
+
embedCode: extractEmbedCodes ? iframe.outerHTML : null
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
// Search in links
|
|
239
|
+
const links = document.querySelectorAll('a[href]');
|
|
240
|
+
links.forEach((link) => {
|
|
241
|
+
const href = link.href;
|
|
242
|
+
for (const [platform, patterns] of Object.entries(hostingPatterns)) {
|
|
243
|
+
if (platforms.includes('all') || platforms.includes(platform)) {
|
|
244
|
+
if (patterns[0].test(href)) {
|
|
245
|
+
const videoId = href.match(patterns[1] || patterns[0]);
|
|
246
|
+
sources.push({
|
|
247
|
+
platform,
|
|
248
|
+
url: href,
|
|
249
|
+
videoId: videoId ? videoId[1] : null,
|
|
250
|
+
type: 'link',
|
|
251
|
+
linkText: link.textContent?.trim() || ''
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
// Search in script content for API calls and video IDs
|
|
258
|
+
const scripts = document.querySelectorAll('script');
|
|
259
|
+
scripts.forEach((script) => {
|
|
260
|
+
const content = script.textContent || '';
|
|
261
|
+
for (const [platform, patterns] of Object.entries(hostingPatterns)) {
|
|
262
|
+
if (platforms.includes('all') || platforms.includes(platform)) {
|
|
263
|
+
const matches = content.match(patterns[1] || patterns[0]);
|
|
264
|
+
if (matches) {
|
|
265
|
+
matches.forEach(match => {
|
|
266
|
+
sources.push({
|
|
267
|
+
platform,
|
|
268
|
+
url: match,
|
|
269
|
+
type: 'script',
|
|
270
|
+
source: 'javascript'
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return sources;
|
|
278
|
+
}, { platforms, extractEmbedCodes, extractAPIKeys });
|
|
279
|
+
return {
|
|
280
|
+
success: true,
|
|
281
|
+
sources: hostingSources,
|
|
282
|
+
platforms: [...new Set(hostingSources.map((s) => s.platform))],
|
|
283
|
+
total: hostingSources.length,
|
|
284
|
+
message: `Found ${hostingSources.length} hosting platform sources`
|
|
285
|
+
};
|
|
286
|
+
}, 'Failed to find video hosting sources');
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// AJAX Finders Handler
|
|
290
|
+
export async function handleAjaxFinders(args) {
|
|
291
|
+
return withWorkflowValidation('ajax_finders', args, async () => {
|
|
292
|
+
return withErrorHandling(async () => {
|
|
293
|
+
const browser = getBrowser();
|
|
294
|
+
const page = getPage();
|
|
295
|
+
if (!browser || !page) {
|
|
296
|
+
throw new Error('Browser not initialized. Call browser_init first.');
|
|
297
|
+
}
|
|
298
|
+
const { interceptXHR = true, interceptFetch = true, recordResponses = true, filterByContentType = ['application/json', 'text/html', 'application/xml'], monitoringDuration = 10000 } = args;
|
|
299
|
+
const ajaxRequests = [];
|
|
300
|
+
// Intercept network requests
|
|
301
|
+
await page.setRequestInterception(true);
|
|
302
|
+
page.on('request', (request) => {
|
|
303
|
+
const resourceType = request.resourceType();
|
|
304
|
+
if (resourceType === 'xhr' || resourceType === 'fetch') {
|
|
305
|
+
ajaxRequests.push({
|
|
306
|
+
url: request.url(),
|
|
307
|
+
method: request.method(),
|
|
308
|
+
headers: request.headers(),
|
|
309
|
+
postData: request.postData(),
|
|
310
|
+
resourceType,
|
|
311
|
+
timestamp: Date.now(),
|
|
312
|
+
type: 'request'
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
request.continue();
|
|
316
|
+
});
|
|
317
|
+
if (recordResponses) {
|
|
318
|
+
page.on('response', async (response) => {
|
|
319
|
+
try {
|
|
320
|
+
const request = response.request();
|
|
321
|
+
const resourceType = request.resourceType();
|
|
322
|
+
if (resourceType === 'xhr' || resourceType === 'fetch') {
|
|
323
|
+
const contentType = response.headers()['content-type'] || '';
|
|
324
|
+
const shouldRecord = filterByContentType.length === 0 ||
|
|
325
|
+
filterByContentType.some((type) => contentType.includes(type));
|
|
326
|
+
if (shouldRecord) {
|
|
327
|
+
let responseBody = '';
|
|
328
|
+
try {
|
|
329
|
+
responseBody = await response.text();
|
|
330
|
+
}
|
|
331
|
+
catch (e) {
|
|
332
|
+
responseBody = '[Unable to read response body]';
|
|
333
|
+
}
|
|
334
|
+
ajaxRequests.push({
|
|
335
|
+
url: response.url(),
|
|
336
|
+
status: response.status(),
|
|
337
|
+
headers: response.headers(),
|
|
338
|
+
contentType,
|
|
339
|
+
body: responseBody.substring(0, 10000), // Limit body size
|
|
340
|
+
timestamp: Date.now(),
|
|
341
|
+
type: 'response'
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
// Ignore response processing errors
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
// Wait for AJAX activity
|
|
352
|
+
await new Promise(resolve => setTimeout(resolve, monitoringDuration));
|
|
353
|
+
await page.setRequestInterception(false);
|
|
354
|
+
// Group requests and responses
|
|
355
|
+
const groupedRequests = ajaxRequests.reduce((acc, item) => {
|
|
356
|
+
const key = item.url;
|
|
357
|
+
if (!acc[key])
|
|
358
|
+
acc[key] = { requests: [], responses: [] };
|
|
359
|
+
if (item.type === 'request') {
|
|
360
|
+
acc[key].requests.push(item);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
acc[key].responses.push(item);
|
|
364
|
+
}
|
|
365
|
+
return acc;
|
|
366
|
+
}, {});
|
|
367
|
+
return {
|
|
368
|
+
success: true,
|
|
369
|
+
ajaxRequests: groupedRequests,
|
|
370
|
+
totalRequests: ajaxRequests.filter(r => r.type === 'request').length,
|
|
371
|
+
totalResponses: ajaxRequests.filter(r => r.type === 'response').length,
|
|
372
|
+
uniqueEndpoints: Object.keys(groupedRequests).length,
|
|
373
|
+
message: `Monitored AJAX activity for ${monitoringDuration}ms`
|
|
374
|
+
};
|
|
375
|
+
}, 'Failed to monitor AJAX requests');
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
// User Agent Finders Handler
|
|
379
|
+
export async function handleUserAgentFinders(args) {
|
|
380
|
+
return withWorkflowValidation('user_agent_finders', args, async () => {
|
|
381
|
+
return withErrorHandling(async () => {
|
|
382
|
+
const browser = getBrowser();
|
|
383
|
+
const page = getPage();
|
|
384
|
+
if (!browser || !page) {
|
|
385
|
+
throw new Error('Browser not initialized. Call browser_init first.');
|
|
386
|
+
}
|
|
387
|
+
const { detectFingerprinting = true, analyzeHeaders = true, findCustomUA = true, trackingDetection = true } = args;
|
|
388
|
+
const userAgentInfo = await page.evaluate((options) => {
|
|
389
|
+
const { detectFingerprinting, analyzeHeaders, findCustomUA, trackingDetection } = options;
|
|
390
|
+
const info = {};
|
|
391
|
+
// Get current user agent
|
|
392
|
+
info.currentUserAgent = navigator.userAgent;
|
|
393
|
+
info.platform = navigator.platform;
|
|
394
|
+
info.language = navigator.language;
|
|
395
|
+
info.languages = navigator.languages;
|
|
396
|
+
// Detect fingerprinting attempts
|
|
397
|
+
if (detectFingerprinting) {
|
|
398
|
+
info.fingerprinting = {
|
|
399
|
+
canvas: !!document.createElement('canvas').getContext,
|
|
400
|
+
webgl: !!document.createElement('canvas').getContext('webgl'),
|
|
401
|
+
audioContext: !!window.AudioContext || !!window.webkitAudioContext,
|
|
402
|
+
webrtc: !!(window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection),
|
|
403
|
+
deviceMemory: navigator.deviceMemory || 'unknown',
|
|
404
|
+
hardwareConcurrency: navigator.hardwareConcurrency || 'unknown',
|
|
405
|
+
maxTouchPoints: navigator.maxTouchPoints || 0
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
// Check for custom UA requirements in scripts
|
|
409
|
+
if (findCustomUA) {
|
|
410
|
+
const scripts = document.querySelectorAll('script');
|
|
411
|
+
const uaRequirements = [];
|
|
412
|
+
scripts.forEach(script => {
|
|
413
|
+
const content = script.textContent || '';
|
|
414
|
+
// Look for User-Agent checks
|
|
415
|
+
const uaPatterns = [
|
|
416
|
+
/userAgent\s*[=!]==?\s*['"]([^'"]+)['"]/gi,
|
|
417
|
+
/navigator\.userAgent\.indexOf\(['"]([^'"]+)['"]\)/gi,
|
|
418
|
+
/User-Agent:\s*['"]([^'"]+)['"]/gi
|
|
419
|
+
];
|
|
420
|
+
uaPatterns.forEach(pattern => {
|
|
421
|
+
const matches = content.match(pattern);
|
|
422
|
+
if (matches) {
|
|
423
|
+
uaRequirements.push(...matches);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
info.customUARequirements = [...new Set(uaRequirements)];
|
|
428
|
+
}
|
|
429
|
+
return info;
|
|
430
|
+
}, { detectFingerprinting, analyzeHeaders, findCustomUA, trackingDetection });
|
|
431
|
+
// Get actual request headers from network
|
|
432
|
+
const requestHeaders = {};
|
|
433
|
+
if (analyzeHeaders) {
|
|
434
|
+
await page.setRequestInterception(true);
|
|
435
|
+
const headerPromise = new Promise((resolve) => {
|
|
436
|
+
page.once('request', (request) => {
|
|
437
|
+
resolve(request.headers());
|
|
438
|
+
request.continue();
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
// Trigger a request to capture headers
|
|
442
|
+
await page.reload({ waitUntil: 'domcontentloaded' });
|
|
443
|
+
const headers = await headerPromise;
|
|
444
|
+
requestHeaders.actual = headers;
|
|
445
|
+
await page.setRequestInterception(false);
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
success: true,
|
|
449
|
+
userAgentInfo,
|
|
450
|
+
requestHeaders,
|
|
451
|
+
message: 'User-Agent analysis completed'
|
|
452
|
+
};
|
|
453
|
+
}, 'Failed to analyze User-Agent');
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
// Export handlers for all specialized tools
|
|
457
|
+
export const specializedToolsHandlers = {
|
|
458
|
+
links_finders: handleLinksFinders,
|
|
459
|
+
video_play_sources_finder: handleVideoPlaySourcesFinder,
|
|
460
|
+
video_player_hostars_sources_finder: handleVideoPlayerHostarsSourcesFinder,
|
|
461
|
+
ajax_finders: handleAjaxFinders,
|
|
462
|
+
user_agent_finders: handleUserAgentFinders,
|
|
463
|
+
// Add more handlers as needed...
|
|
464
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,8 @@ import { handleFullPageScreenshot, handleElementScreenshot, handlePDFGeneration,
|
|
|
45
45
|
import { handleRESTAPIEndpointFinder, handleWebhookSupport, handleAllWebsiteAPIFinder } from './handlers/api-integration-handlers.js';
|
|
46
46
|
// Import video extraction handlers
|
|
47
47
|
import { handleHtmlElementsExtraction, handleNetworkVideoExtraction, handleVideoSelectorGeneration, handleComprehensiveVideoExtraction, handleURLRedirectTrace } from './handlers/video-extraction-handlers.js';
|
|
48
|
+
// Import specialized tools handlers
|
|
49
|
+
import { handleLinksFinders, handleVideoPlaySourcesFinder, handleVideoPlayerHostarsSourcesFinder, handleAjaxFinders, handleUserAgentFinders } from './handlers/specialized-tools-handlers.js';
|
|
48
50
|
console.error('🔍 [DEBUG] All modules loaded successfully');
|
|
49
51
|
console.error(`🔍 [DEBUG] Server info: ${JSON.stringify(SERVER_INFO)}`);
|
|
50
52
|
console.error(`🔍 [DEBUG] Available tools: ${TOOLS.length} tools loaded`);
|
|
@@ -246,6 +248,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
246
248
|
return await handleComprehensiveVideoExtraction(args);
|
|
247
249
|
case TOOL_NAMES.URL_REDIRECT_TRACE:
|
|
248
250
|
return await handleURLRedirectTrace(args);
|
|
251
|
+
// Specialized Video and Links Extraction Tools
|
|
252
|
+
case TOOL_NAMES.LINKS_FINDERS:
|
|
253
|
+
return await handleLinksFinders(args);
|
|
254
|
+
case TOOL_NAMES.VIDEO_PLAY_SOURCES_FINDER:
|
|
255
|
+
return await handleVideoPlaySourcesFinder(args);
|
|
256
|
+
case TOOL_NAMES.VIDEO_PLAYER_HOSTARS_SOURCES_FINDER:
|
|
257
|
+
return await handleVideoPlayerHostarsSourcesFinder(args);
|
|
258
|
+
case TOOL_NAMES.AJAX_FINDERS:
|
|
259
|
+
return await handleAjaxFinders(args);
|
|
260
|
+
case TOOL_NAMES.USER_AGENT_FINDERS:
|
|
261
|
+
return await handleUserAgentFinders(args);
|
|
262
|
+
// Regex Pattern Finders (alias for existing regex_pattern_matcher)
|
|
263
|
+
case TOOL_NAMES.REGEX_PATTERN_FINDERS:
|
|
264
|
+
return await handleRegexPatternMatcher(args);
|
|
249
265
|
default:
|
|
250
266
|
throw new Error(`Unknown tool: ${name}`);
|
|
251
267
|
}
|
package/dist/tool-definitions.js
CHANGED
|
@@ -1106,6 +1106,435 @@ export const TOOLS = [
|
|
|
1106
1106
|
required: ['url'],
|
|
1107
1107
|
},
|
|
1108
1108
|
},
|
|
1109
|
+
// Specialized Video and Links Extraction Tools
|
|
1110
|
+
{
|
|
1111
|
+
name: 'links_finders',
|
|
1112
|
+
description: 'Find and extract all types of links from page (HTTP, HTTPS, FTP, email, phone, etc.)',
|
|
1113
|
+
inputSchema: {
|
|
1114
|
+
type: 'object',
|
|
1115
|
+
properties: {
|
|
1116
|
+
includeExternal: {
|
|
1117
|
+
type: 'boolean',
|
|
1118
|
+
description: 'Include external links',
|
|
1119
|
+
default: true
|
|
1120
|
+
},
|
|
1121
|
+
includeInternal: {
|
|
1122
|
+
type: 'boolean',
|
|
1123
|
+
description: 'Include internal links',
|
|
1124
|
+
default: true
|
|
1125
|
+
},
|
|
1126
|
+
includeMediaLinks: {
|
|
1127
|
+
type: 'boolean',
|
|
1128
|
+
description: 'Include media file links',
|
|
1129
|
+
default: true
|
|
1130
|
+
},
|
|
1131
|
+
includeEmailPhone: {
|
|
1132
|
+
type: 'boolean',
|
|
1133
|
+
description: 'Include email and phone links',
|
|
1134
|
+
default: false
|
|
1135
|
+
},
|
|
1136
|
+
filterDomains: {
|
|
1137
|
+
type: 'array',
|
|
1138
|
+
description: 'Filter links by specific domains',
|
|
1139
|
+
items: { type: 'string' }
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
name: 'video_play_sources_finder',
|
|
1146
|
+
description: 'Find direct video play sources and streaming URLs',
|
|
1147
|
+
inputSchema: {
|
|
1148
|
+
type: 'object',
|
|
1149
|
+
properties: {
|
|
1150
|
+
includeHLS: {
|
|
1151
|
+
type: 'boolean',
|
|
1152
|
+
description: 'Include HLS (.m3u8) sources',
|
|
1153
|
+
default: true
|
|
1154
|
+
},
|
|
1155
|
+
includeDASH: {
|
|
1156
|
+
type: 'boolean',
|
|
1157
|
+
description: 'Include DASH (.mpd) sources',
|
|
1158
|
+
default: true
|
|
1159
|
+
},
|
|
1160
|
+
includeDirectMP4: {
|
|
1161
|
+
type: 'boolean',
|
|
1162
|
+
description: 'Include direct MP4 sources',
|
|
1163
|
+
default: true
|
|
1164
|
+
},
|
|
1165
|
+
includeBlob: {
|
|
1166
|
+
type: 'boolean',
|
|
1167
|
+
description: 'Include blob URLs',
|
|
1168
|
+
default: true
|
|
1169
|
+
},
|
|
1170
|
+
recordingDuration: {
|
|
1171
|
+
type: 'number',
|
|
1172
|
+
description: 'Network recording duration (ms)',
|
|
1173
|
+
default: 15000
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
{
|
|
1179
|
+
name: 'video_player_hostars_sources_finder',
|
|
1180
|
+
description: 'Find video sources from popular hosting platforms (YouTube, Vimeo, Dailymotion, etc.)',
|
|
1181
|
+
inputSchema: {
|
|
1182
|
+
type: 'object',
|
|
1183
|
+
properties: {
|
|
1184
|
+
platforms: {
|
|
1185
|
+
type: 'array',
|
|
1186
|
+
description: 'Specific platforms to search',
|
|
1187
|
+
items: {
|
|
1188
|
+
type: 'string',
|
|
1189
|
+
enum: ['youtube', 'vimeo', 'dailymotion', 'twitch', 'facebook', 'instagram', 'tiktok', 'all']
|
|
1190
|
+
},
|
|
1191
|
+
default: ['all']
|
|
1192
|
+
},
|
|
1193
|
+
extractEmbedCodes: {
|
|
1194
|
+
type: 'boolean',
|
|
1195
|
+
description: 'Extract embed codes',
|
|
1196
|
+
default: true
|
|
1197
|
+
},
|
|
1198
|
+
extractAPIKeys: {
|
|
1199
|
+
type: 'boolean',
|
|
1200
|
+
description: 'Extract API keys from network requests',
|
|
1201
|
+
default: false
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
name: 'video_sources_links_finders',
|
|
1208
|
+
description: 'Comprehensive video source links extraction from all possible locations',
|
|
1209
|
+
inputSchema: {
|
|
1210
|
+
type: 'object',
|
|
1211
|
+
properties: {
|
|
1212
|
+
searchInJS: {
|
|
1213
|
+
type: 'boolean',
|
|
1214
|
+
description: 'Search in JavaScript code',
|
|
1215
|
+
default: true
|
|
1216
|
+
},
|
|
1217
|
+
searchInJSON: {
|
|
1218
|
+
type: 'boolean',
|
|
1219
|
+
description: 'Search in JSON responses',
|
|
1220
|
+
default: true
|
|
1221
|
+
},
|
|
1222
|
+
searchInCSS: {
|
|
1223
|
+
type: 'boolean',
|
|
1224
|
+
description: 'Search in CSS files',
|
|
1225
|
+
default: false
|
|
1226
|
+
},
|
|
1227
|
+
searchInComments: {
|
|
1228
|
+
type: 'boolean',
|
|
1229
|
+
description: 'Search in HTML comments',
|
|
1230
|
+
default: true
|
|
1231
|
+
},
|
|
1232
|
+
deepScan: {
|
|
1233
|
+
type: 'boolean',
|
|
1234
|
+
description: 'Enable deep scanning mode',
|
|
1235
|
+
default: true
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
{
|
|
1241
|
+
name: 'video_download_page',
|
|
1242
|
+
description: 'Find and navigate to video download pages',
|
|
1243
|
+
inputSchema: {
|
|
1244
|
+
type: 'object',
|
|
1245
|
+
properties: {
|
|
1246
|
+
searchKeywords: {
|
|
1247
|
+
type: 'array',
|
|
1248
|
+
description: 'Keywords to identify download pages',
|
|
1249
|
+
items: { type: 'string' },
|
|
1250
|
+
default: ['download', 'save', 'get', 'grab']
|
|
1251
|
+
},
|
|
1252
|
+
followRedirects: {
|
|
1253
|
+
type: 'boolean',
|
|
1254
|
+
description: 'Follow redirects to find actual download pages',
|
|
1255
|
+
default: true
|
|
1256
|
+
},
|
|
1257
|
+
maxDepth: {
|
|
1258
|
+
type: 'number',
|
|
1259
|
+
description: 'Maximum navigation depth',
|
|
1260
|
+
default: 3
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
},
|
|
1265
|
+
{
|
|
1266
|
+
name: 'video_sources_extracts',
|
|
1267
|
+
description: 'Extract and process video sources with metadata',
|
|
1268
|
+
inputSchema: {
|
|
1269
|
+
type: 'object',
|
|
1270
|
+
properties: {
|
|
1271
|
+
includeMetadata: {
|
|
1272
|
+
type: 'boolean',
|
|
1273
|
+
description: 'Include video metadata (duration, resolution, codec)',
|
|
1274
|
+
default: true
|
|
1275
|
+
},
|
|
1276
|
+
validateSources: {
|
|
1277
|
+
type: 'boolean',
|
|
1278
|
+
description: 'Validate source URLs accessibility',
|
|
1279
|
+
default: false
|
|
1280
|
+
},
|
|
1281
|
+
extractThumbnails: {
|
|
1282
|
+
type: 'boolean',
|
|
1283
|
+
description: 'Extract thumbnail URLs',
|
|
1284
|
+
default: true
|
|
1285
|
+
},
|
|
1286
|
+
extractSubtitles: {
|
|
1287
|
+
type: 'boolean',
|
|
1288
|
+
description: 'Extract subtitle tracks',
|
|
1289
|
+
default: true
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
name: 'video_download_button',
|
|
1296
|
+
description: 'Find and interact with video download buttons',
|
|
1297
|
+
inputSchema: {
|
|
1298
|
+
type: 'object',
|
|
1299
|
+
properties: {
|
|
1300
|
+
buttonSelectors: {
|
|
1301
|
+
type: 'array',
|
|
1302
|
+
description: 'Custom button selectors to search',
|
|
1303
|
+
items: { type: 'string' }
|
|
1304
|
+
},
|
|
1305
|
+
clickButton: {
|
|
1306
|
+
type: 'boolean',
|
|
1307
|
+
description: 'Automatically click found download buttons',
|
|
1308
|
+
default: false
|
|
1309
|
+
},
|
|
1310
|
+
waitAfterClick: {
|
|
1311
|
+
type: 'number',
|
|
1312
|
+
description: 'Wait time after clicking (ms)',
|
|
1313
|
+
default: 3000
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
name: 'video_play_push_sources',
|
|
1320
|
+
description: 'Find video sources from push/streaming services',
|
|
1321
|
+
inputSchema: {
|
|
1322
|
+
type: 'object',
|
|
1323
|
+
properties: {
|
|
1324
|
+
includeWebSocket: {
|
|
1325
|
+
type: 'boolean',
|
|
1326
|
+
description: 'Include WebSocket streaming sources',
|
|
1327
|
+
default: true
|
|
1328
|
+
},
|
|
1329
|
+
includeWebRTC: {
|
|
1330
|
+
type: 'boolean',
|
|
1331
|
+
description: 'Include WebRTC sources',
|
|
1332
|
+
default: true
|
|
1333
|
+
},
|
|
1334
|
+
includePush: {
|
|
1335
|
+
type: 'boolean',
|
|
1336
|
+
description: 'Include server push sources',
|
|
1337
|
+
default: true
|
|
1338
|
+
},
|
|
1339
|
+
monitoringDuration: {
|
|
1340
|
+
type: 'number',
|
|
1341
|
+
description: 'Duration to monitor for push sources (ms)',
|
|
1342
|
+
default: 20000
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
name: 'original_video_hosters_finder',
|
|
1349
|
+
description: 'Find original video hosting sources bypassing CDNs',
|
|
1350
|
+
inputSchema: {
|
|
1351
|
+
type: 'object',
|
|
1352
|
+
properties: {
|
|
1353
|
+
bypassCDN: {
|
|
1354
|
+
type: 'boolean',
|
|
1355
|
+
description: 'Attempt to bypass CDN and find original sources',
|
|
1356
|
+
default: true
|
|
1357
|
+
},
|
|
1358
|
+
traceOrigin: {
|
|
1359
|
+
type: 'boolean',
|
|
1360
|
+
description: 'Trace back to original hosting domain',
|
|
1361
|
+
default: true
|
|
1362
|
+
},
|
|
1363
|
+
includeBackupSources: {
|
|
1364
|
+
type: 'boolean',
|
|
1365
|
+
description: 'Include backup/mirror sources',
|
|
1366
|
+
default: true
|
|
1367
|
+
},
|
|
1368
|
+
deepNetworkAnalysis: {
|
|
1369
|
+
type: 'boolean',
|
|
1370
|
+
description: 'Perform deep network analysis',
|
|
1371
|
+
default: true
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
name: 'ajax_finders',
|
|
1378
|
+
description: 'Find and monitor AJAX requests and endpoints',
|
|
1379
|
+
inputSchema: {
|
|
1380
|
+
type: 'object',
|
|
1381
|
+
properties: {
|
|
1382
|
+
interceptXHR: {
|
|
1383
|
+
type: 'boolean',
|
|
1384
|
+
description: 'Intercept XMLHttpRequest calls',
|
|
1385
|
+
default: true
|
|
1386
|
+
},
|
|
1387
|
+
interceptFetch: {
|
|
1388
|
+
type: 'boolean',
|
|
1389
|
+
description: 'Intercept Fetch API calls',
|
|
1390
|
+
default: true
|
|
1391
|
+
},
|
|
1392
|
+
recordResponses: {
|
|
1393
|
+
type: 'boolean',
|
|
1394
|
+
description: 'Record AJAX response data',
|
|
1395
|
+
default: true
|
|
1396
|
+
},
|
|
1397
|
+
filterByContentType: {
|
|
1398
|
+
type: 'array',
|
|
1399
|
+
description: 'Filter by response content types',
|
|
1400
|
+
items: { type: 'string' },
|
|
1401
|
+
default: ['application/json', 'text/html', 'application/xml']
|
|
1402
|
+
},
|
|
1403
|
+
monitoringDuration: {
|
|
1404
|
+
type: 'number',
|
|
1405
|
+
description: 'Duration to monitor AJAX calls (ms)',
|
|
1406
|
+
default: 10000
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
name: 'ajax_extracts',
|
|
1413
|
+
description: 'Extract and process data from AJAX responses',
|
|
1414
|
+
inputSchema: {
|
|
1415
|
+
type: 'object',
|
|
1416
|
+
properties: {
|
|
1417
|
+
parseJSON: {
|
|
1418
|
+
type: 'boolean',
|
|
1419
|
+
description: 'Parse JSON responses',
|
|
1420
|
+
default: true
|
|
1421
|
+
},
|
|
1422
|
+
parseXML: {
|
|
1423
|
+
type: 'boolean',
|
|
1424
|
+
description: 'Parse XML responses',
|
|
1425
|
+
default: true
|
|
1426
|
+
},
|
|
1427
|
+
extractVideoSources: {
|
|
1428
|
+
type: 'boolean',
|
|
1429
|
+
description: 'Extract video sources from AJAX responses',
|
|
1430
|
+
default: true
|
|
1431
|
+
},
|
|
1432
|
+
extractAPIEndpoints: {
|
|
1433
|
+
type: 'boolean',
|
|
1434
|
+
description: 'Extract API endpoints from responses',
|
|
1435
|
+
default: true
|
|
1436
|
+
},
|
|
1437
|
+
saveRawData: {
|
|
1438
|
+
type: 'boolean',
|
|
1439
|
+
description: 'Save raw response data',
|
|
1440
|
+
default: false
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
name: 'user_agent_finders',
|
|
1447
|
+
description: 'Find and analyze User-Agent strings and browser fingerprinting',
|
|
1448
|
+
inputSchema: {
|
|
1449
|
+
type: 'object',
|
|
1450
|
+
properties: {
|
|
1451
|
+
detectFingerprinting: {
|
|
1452
|
+
type: 'boolean',
|
|
1453
|
+
description: 'Detect browser fingerprinting attempts',
|
|
1454
|
+
default: true
|
|
1455
|
+
},
|
|
1456
|
+
analyzeHeaders: {
|
|
1457
|
+
type: 'boolean',
|
|
1458
|
+
description: 'Analyze all browser headers',
|
|
1459
|
+
default: true
|
|
1460
|
+
},
|
|
1461
|
+
findCustomUA: {
|
|
1462
|
+
type: 'boolean',
|
|
1463
|
+
description: 'Find custom User-Agent requirements',
|
|
1464
|
+
default: true
|
|
1465
|
+
},
|
|
1466
|
+
trackingDetection: {
|
|
1467
|
+
type: 'boolean',
|
|
1468
|
+
description: 'Detect tracking mechanisms',
|
|
1469
|
+
default: true
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
name: 'user_agent_extracts',
|
|
1476
|
+
description: 'Extract and generate User-Agent strings for bypassing restrictions',
|
|
1477
|
+
inputSchema: {
|
|
1478
|
+
type: 'object',
|
|
1479
|
+
properties: {
|
|
1480
|
+
generateMobile: {
|
|
1481
|
+
type: 'boolean',
|
|
1482
|
+
description: 'Generate mobile User-Agent strings',
|
|
1483
|
+
default: true
|
|
1484
|
+
},
|
|
1485
|
+
generateDesktop: {
|
|
1486
|
+
type: 'boolean',
|
|
1487
|
+
description: 'Generate desktop User-Agent strings',
|
|
1488
|
+
default: true
|
|
1489
|
+
},
|
|
1490
|
+
generateBot: {
|
|
1491
|
+
type: 'boolean',
|
|
1492
|
+
description: 'Generate bot/crawler User-Agent strings',
|
|
1493
|
+
default: false
|
|
1494
|
+
},
|
|
1495
|
+
targetPlatforms: {
|
|
1496
|
+
type: 'array',
|
|
1497
|
+
description: 'Target specific platforms',
|
|
1498
|
+
items: {
|
|
1499
|
+
type: 'string',
|
|
1500
|
+
enum: ['windows', 'mac', 'linux', 'android', 'ios']
|
|
1501
|
+
},
|
|
1502
|
+
default: ['windows', 'mac', 'android']
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
name: 'regex_pattern_finders',
|
|
1509
|
+
description: 'Advanced regex pattern finding and matching (alias for regex_pattern_matcher)',
|
|
1510
|
+
inputSchema: {
|
|
1511
|
+
type: 'object',
|
|
1512
|
+
properties: {
|
|
1513
|
+
patterns: {
|
|
1514
|
+
type: 'array',
|
|
1515
|
+
description: 'Array of regex patterns to search',
|
|
1516
|
+
items: { type: 'string' }
|
|
1517
|
+
},
|
|
1518
|
+
flags: {
|
|
1519
|
+
type: 'string',
|
|
1520
|
+
description: 'Regex flags (g, i, m, s, u, y)',
|
|
1521
|
+
default: 'gi'
|
|
1522
|
+
},
|
|
1523
|
+
extractGroups: {
|
|
1524
|
+
type: 'boolean',
|
|
1525
|
+
description: 'Extract capture groups from matches',
|
|
1526
|
+
default: true
|
|
1527
|
+
},
|
|
1528
|
+
searchScope: {
|
|
1529
|
+
type: 'string',
|
|
1530
|
+
enum: ['html', 'text', 'scripts', 'network', 'all'],
|
|
1531
|
+
description: 'Scope of search',
|
|
1532
|
+
default: 'all'
|
|
1533
|
+
}
|
|
1534
|
+
},
|
|
1535
|
+
required: ['patterns']
|
|
1536
|
+
}
|
|
1537
|
+
},
|
|
1109
1538
|
];
|
|
1110
1539
|
// Tool name constants for type safety
|
|
1111
1540
|
export const TOOL_NAMES = {
|
|
@@ -1189,6 +1618,21 @@ export const TOOL_NAMES = {
|
|
|
1189
1618
|
VIDEO_SELECTOR_GENERATION: 'video_selector_generation',
|
|
1190
1619
|
COMPREHENSIVE_VIDEO_EXTRACTION: 'comprehensive_video_extraction',
|
|
1191
1620
|
URL_REDIRECT_TRACE: 'url_redirect_trace',
|
|
1621
|
+
// Specialized Video and Links Extraction Tools
|
|
1622
|
+
LINKS_FINDERS: 'links_finders',
|
|
1623
|
+
VIDEO_PLAY_SOURCES_FINDER: 'video_play_sources_finder',
|
|
1624
|
+
VIDEO_PLAYER_HOSTARS_SOURCES_FINDER: 'video_player_hostars_sources_finder',
|
|
1625
|
+
VIDEO_SOURCES_LINKS_FINDERS: 'video_sources_links_finders',
|
|
1626
|
+
VIDEO_DOWNLOAD_PAGE: 'video_download_page',
|
|
1627
|
+
VIDEO_SOURCES_EXTRACTS: 'video_sources_extracts',
|
|
1628
|
+
VIDEO_DOWNLOAD_BUTTON: 'video_download_button',
|
|
1629
|
+
VIDEO_PLAY_PUSH_SOURCES: 'video_play_push_sources',
|
|
1630
|
+
ORIGINAL_VIDEO_HOSTERS_FINDER: 'original_video_hosters_finder',
|
|
1631
|
+
AJAX_FINDERS: 'ajax_finders',
|
|
1632
|
+
AJAX_EXTRACTS: 'ajax_extracts',
|
|
1633
|
+
USER_AGENT_FINDERS: 'user_agent_finders',
|
|
1634
|
+
USER_AGENT_EXTRACTS: 'user_agent_extracts',
|
|
1635
|
+
REGEX_PATTERN_FINDERS: 'regex_pattern_finders',
|
|
1192
1636
|
};
|
|
1193
1637
|
// Tool categories for organization
|
|
1194
1638
|
export const TOOL_CATEGORIES = {
|