brave-real-browser-mcp-server 2.9.7 → 2.9.9
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/dist/browser-manager.js +7 -0
- package/dist/handlers/video-extraction-handlers.js +373 -0
- package/dist/index.js +13 -0
- package/dist/tool-definitions.js +138 -0
- package/dist/video-extraction/dom-extractors.js +421 -0
- package/dist/video-extraction/network-extractors.js +421 -0
- package/dist/video-extraction/types.js +61 -0
- package/package.json +2 -2
package/dist/browser-manager.js
CHANGED
|
@@ -907,3 +907,10 @@ export function getContentPriorityConfig() {
|
|
|
907
907
|
export function updateContentPriorityConfig(config) {
|
|
908
908
|
contentPriorityConfig = { ...contentPriorityConfig, ...config };
|
|
909
909
|
}
|
|
910
|
+
// Additional convenience exports for video extraction modules
|
|
911
|
+
export function getBrowser() {
|
|
912
|
+
return browserInstance;
|
|
913
|
+
}
|
|
914
|
+
export function getPage() {
|
|
915
|
+
return pageInstance;
|
|
916
|
+
}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
// Video extraction handlers for MCP tools
|
|
2
|
+
import { ExtractionStrategy } from '../video-extraction/types.js';
|
|
3
|
+
import { htmlElementsFinder, videoSelectors } from '../video-extraction/dom-extractors.js';
|
|
4
|
+
import { networkRecorder, requestChainTracer } from '../video-extraction/network-extractors.js';
|
|
5
|
+
import { validateWorkflow, recordExecution } from '../workflow-validation.js';
|
|
6
|
+
import { withErrorHandling } from '../system-utils.js';
|
|
7
|
+
import { getPage } from '../browser-manager.js';
|
|
8
|
+
// Wrapper function for workflow validation
|
|
9
|
+
async function withVideoExtractionWorkflowValidation(toolName, operation) {
|
|
10
|
+
// Validate workflow state
|
|
11
|
+
const workflowResult = validateWorkflow(toolName);
|
|
12
|
+
if (!workflowResult.isValid) {
|
|
13
|
+
throw new Error(`Workflow validation failed for ${toolName}: ${workflowResult.errorMessage}`);
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const result = await operation();
|
|
17
|
+
recordExecution(toolName, {}, true);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
recordExecution(toolName, {}, false, error instanceof Error ? error.message : String(error));
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// HTML Elements Video Extractor
|
|
26
|
+
export async function handleHtmlElementsExtraction(args) {
|
|
27
|
+
return withVideoExtractionWorkflowValidation('html_elements_extraction', async () => {
|
|
28
|
+
return withErrorHandling(async () => {
|
|
29
|
+
const startTime = Date.now();
|
|
30
|
+
const allSources = [];
|
|
31
|
+
const errors = [];
|
|
32
|
+
const warnings = [];
|
|
33
|
+
try {
|
|
34
|
+
// Initialize HTML elements finder
|
|
35
|
+
await htmlElementsFinder.initialize();
|
|
36
|
+
// Extract from video tags
|
|
37
|
+
if (args.extractVideoTags !== false) {
|
|
38
|
+
try {
|
|
39
|
+
const videoTagSources = await htmlElementsFinder.findVideoTags();
|
|
40
|
+
allSources.push(...videoTagSources);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
errors.push({
|
|
44
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
45
|
+
message: 'Failed to extract video tags',
|
|
46
|
+
details: error,
|
|
47
|
+
isFatal: false
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Extract from iframes
|
|
52
|
+
if (args.extractIframes !== false) {
|
|
53
|
+
try {
|
|
54
|
+
const iframeSources = await htmlElementsFinder.findIframeSources();
|
|
55
|
+
allSources.push(...iframeSources);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
errors.push({
|
|
59
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
60
|
+
message: 'Failed to extract iframe sources',
|
|
61
|
+
details: error,
|
|
62
|
+
isFatal: false
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Extract from embeds
|
|
67
|
+
if (args.extractEmbeds !== false) {
|
|
68
|
+
try {
|
|
69
|
+
const embedSources = await htmlElementsFinder.findEmbedSources();
|
|
70
|
+
allSources.push(...embedSources);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
errors.push({
|
|
74
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
75
|
+
message: 'Failed to extract embed sources',
|
|
76
|
+
details: error,
|
|
77
|
+
isFatal: false
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Extract from meta tags
|
|
82
|
+
if (args.extractMetaTags !== false) {
|
|
83
|
+
try {
|
|
84
|
+
const metaSources = await htmlElementsFinder.findMetaVideoSources();
|
|
85
|
+
allSources.push(...metaSources);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
errors.push({
|
|
89
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
90
|
+
message: 'Failed to extract meta tag sources',
|
|
91
|
+
details: error,
|
|
92
|
+
isFatal: false
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Extract from data attributes
|
|
97
|
+
if (args.extractDataAttributes !== false) {
|
|
98
|
+
try {
|
|
99
|
+
const dataSources = await htmlElementsFinder.findDataAttributesSources();
|
|
100
|
+
allSources.push(...dataSources);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
errors.push({
|
|
104
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
105
|
+
message: 'Failed to extract data attribute sources',
|
|
106
|
+
details: error,
|
|
107
|
+
isFatal: false
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Get current page info for metadata
|
|
112
|
+
const page = getPage();
|
|
113
|
+
const pageUrl = page ? await page.url() : 'unknown';
|
|
114
|
+
const pageTitle = page ? await page.title() : undefined;
|
|
115
|
+
// Deduplicate sources
|
|
116
|
+
const uniqueSources = deduplicateSources(allSources);
|
|
117
|
+
const result = {
|
|
118
|
+
sources: uniqueSources,
|
|
119
|
+
metadata: {
|
|
120
|
+
title: pageTitle,
|
|
121
|
+
extractionTime: Date.now() - startTime,
|
|
122
|
+
strategiesUsed: [ExtractionStrategy.DOM_ANALYSIS],
|
|
123
|
+
hostersFound: [...new Set(uniqueSources.map(s => s.hoster).filter(Boolean))]
|
|
124
|
+
},
|
|
125
|
+
errors,
|
|
126
|
+
warnings
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
content: result,
|
|
130
|
+
isError: false
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw new Error(`HTML elements extraction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
135
|
+
}
|
|
136
|
+
}, 'handleHtmlElementsExtraction');
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// Network Recording Video Extractor
|
|
140
|
+
export async function handleNetworkVideoExtraction(args) {
|
|
141
|
+
return withVideoExtractionWorkflowValidation('network_video_extraction', async () => {
|
|
142
|
+
return withErrorHandling(async () => {
|
|
143
|
+
const startTime = Date.now();
|
|
144
|
+
const errors = [];
|
|
145
|
+
const warnings = [];
|
|
146
|
+
try {
|
|
147
|
+
// Start network recording
|
|
148
|
+
await networkRecorder.startRecording({
|
|
149
|
+
interceptRequests: args.interceptRequests || false,
|
|
150
|
+
captureResponses: args.captureResponses || true,
|
|
151
|
+
filterResourceTypes: args.filterResourceTypes,
|
|
152
|
+
maxRecords: args.maxRecords || 1000
|
|
153
|
+
});
|
|
154
|
+
// Record for specified duration or default 10 seconds
|
|
155
|
+
const duration = args.recordingDuration || 10000;
|
|
156
|
+
await new Promise(resolve => setTimeout(resolve, duration));
|
|
157
|
+
// Stop recording and get video sources
|
|
158
|
+
const requests = await networkRecorder.stopRecording();
|
|
159
|
+
const videoSources = await networkRecorder.getVideoRequests();
|
|
160
|
+
// Get API endpoints that might contain video data
|
|
161
|
+
const apiEndpoints = await networkRecorder.getAPIEndpoints();
|
|
162
|
+
if (apiEndpoints.length > 0) {
|
|
163
|
+
warnings.push(`Found ${apiEndpoints.length} API endpoints that might contain video data`);
|
|
164
|
+
}
|
|
165
|
+
// Extract tokens for authentication
|
|
166
|
+
const tokens = await networkRecorder.extractTokensFromRequests();
|
|
167
|
+
if (tokens.authTokens.length > 0) {
|
|
168
|
+
warnings.push(`Found ${tokens.authTokens.length} authentication tokens`);
|
|
169
|
+
}
|
|
170
|
+
// Get current page info for metadata
|
|
171
|
+
const page = getPage();
|
|
172
|
+
const pageUrl = page ? await page.url() : 'unknown';
|
|
173
|
+
const pageTitle = page ? await page.title() : undefined;
|
|
174
|
+
const result = {
|
|
175
|
+
sources: videoSources,
|
|
176
|
+
metadata: {
|
|
177
|
+
title: pageTitle,
|
|
178
|
+
extractionTime: Date.now() - startTime,
|
|
179
|
+
strategiesUsed: [ExtractionStrategy.NETWORK_RECORDING],
|
|
180
|
+
hostersFound: [...new Set(videoSources.map(s => s.hoster).filter(Boolean))]
|
|
181
|
+
},
|
|
182
|
+
errors,
|
|
183
|
+
warnings
|
|
184
|
+
};
|
|
185
|
+
return {
|
|
186
|
+
content: result,
|
|
187
|
+
isError: false
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw new Error(`Network video extraction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
192
|
+
}
|
|
193
|
+
}, 'handleNetworkVideoExtraction');
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
// Video Selectors Generator
|
|
197
|
+
export async function handleVideoSelectorGeneration(args) {
|
|
198
|
+
return withVideoExtractionWorkflowValidation('video_selector_generation', async () => {
|
|
199
|
+
return withErrorHandling(async () => {
|
|
200
|
+
try {
|
|
201
|
+
await videoSelectors.initialize();
|
|
202
|
+
const selectors = await videoSelectors.generateVideoSelectors();
|
|
203
|
+
return {
|
|
204
|
+
content: selectors,
|
|
205
|
+
isError: false
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
throw new Error(`Video selector generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
210
|
+
}
|
|
211
|
+
}, 'handleVideoSelectorGeneration');
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// Comprehensive Video Extraction (combines all strategies)
|
|
215
|
+
export async function handleComprehensiveVideoExtraction(args) {
|
|
216
|
+
return withVideoExtractionWorkflowValidation('comprehensive_video_extraction', async () => {
|
|
217
|
+
return withErrorHandling(async () => {
|
|
218
|
+
const startTime = Date.now();
|
|
219
|
+
const allSources = [];
|
|
220
|
+
const errors = [];
|
|
221
|
+
const warnings = [];
|
|
222
|
+
const strategiesUsed = [];
|
|
223
|
+
try {
|
|
224
|
+
// DOM Analysis
|
|
225
|
+
if (args.enableDOMAnalysis !== false) {
|
|
226
|
+
try {
|
|
227
|
+
const domResult = await handleHtmlElementsExtraction({
|
|
228
|
+
extractVideoTags: true,
|
|
229
|
+
extractIframes: true,
|
|
230
|
+
extractEmbeds: true,
|
|
231
|
+
extractMetaTags: true,
|
|
232
|
+
extractDataAttributes: true
|
|
233
|
+
});
|
|
234
|
+
allSources.push(...domResult.content.sources);
|
|
235
|
+
errors.push(...domResult.content.errors);
|
|
236
|
+
warnings.push(...domResult.content.warnings);
|
|
237
|
+
strategiesUsed.push(ExtractionStrategy.DOM_ANALYSIS);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
errors.push({
|
|
241
|
+
strategy: ExtractionStrategy.DOM_ANALYSIS,
|
|
242
|
+
message: 'DOM analysis failed',
|
|
243
|
+
details: error,
|
|
244
|
+
isFatal: false
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Network Recording
|
|
249
|
+
if (args.enableNetworkRecording !== false) {
|
|
250
|
+
try {
|
|
251
|
+
const networkResult = await handleNetworkVideoExtraction({
|
|
252
|
+
interceptRequests: false,
|
|
253
|
+
captureResponses: true,
|
|
254
|
+
recordingDuration: args.recordingDuration || 10000
|
|
255
|
+
});
|
|
256
|
+
allSources.push(...networkResult.content.sources);
|
|
257
|
+
errors.push(...networkResult.content.errors);
|
|
258
|
+
warnings.push(...networkResult.content.warnings);
|
|
259
|
+
strategiesUsed.push(ExtractionStrategy.NETWORK_RECORDING);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
errors.push({
|
|
263
|
+
strategy: ExtractionStrategy.NETWORK_RECORDING,
|
|
264
|
+
message: 'Network recording failed',
|
|
265
|
+
details: error,
|
|
266
|
+
isFatal: false
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Filter by formats if specified
|
|
271
|
+
let filteredSources = allSources;
|
|
272
|
+
if (args.filterFormats && args.filterFormats.length > 0) {
|
|
273
|
+
filteredSources = allSources.filter(source => args.filterFormats.includes(source.format));
|
|
274
|
+
if (filteredSources.length < allSources.length) {
|
|
275
|
+
warnings.push(`Filtered ${allSources.length - filteredSources.length} sources by format`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Deduplicate and limit sources
|
|
279
|
+
let uniqueSources = deduplicateSources(filteredSources);
|
|
280
|
+
if (args.maxSources && uniqueSources.length > args.maxSources) {
|
|
281
|
+
// Sort by confidence and keep top sources
|
|
282
|
+
uniqueSources = uniqueSources
|
|
283
|
+
.sort((a, b) => b.confidence - a.confidence)
|
|
284
|
+
.slice(0, args.maxSources);
|
|
285
|
+
warnings.push(`Limited results to top ${args.maxSources} sources by confidence`);
|
|
286
|
+
}
|
|
287
|
+
// Get current page info for metadata
|
|
288
|
+
const page = getPage();
|
|
289
|
+
const pageUrl = page ? await page.url() : 'unknown';
|
|
290
|
+
const pageTitle = page ? await page.title() : undefined;
|
|
291
|
+
const result = {
|
|
292
|
+
sources: uniqueSources,
|
|
293
|
+
metadata: {
|
|
294
|
+
title: pageTitle,
|
|
295
|
+
extractionTime: Date.now() - startTime,
|
|
296
|
+
strategiesUsed,
|
|
297
|
+
hostersFound: [...new Set(uniqueSources.map(s => s.hoster).filter(Boolean))]
|
|
298
|
+
},
|
|
299
|
+
errors,
|
|
300
|
+
warnings
|
|
301
|
+
};
|
|
302
|
+
return {
|
|
303
|
+
content: result,
|
|
304
|
+
isError: false
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
throw new Error(`Comprehensive video extraction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
309
|
+
}
|
|
310
|
+
}, 'handleComprehensiveVideoExtraction');
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// URL Redirect Tracer
|
|
314
|
+
export async function handleURLRedirectTrace(args) {
|
|
315
|
+
return withVideoExtractionWorkflowValidation('url_redirect_trace', async () => {
|
|
316
|
+
return withErrorHandling(async () => {
|
|
317
|
+
try {
|
|
318
|
+
// Start recording to capture redirects
|
|
319
|
+
await networkRecorder.startRecording({
|
|
320
|
+
interceptRequests: false,
|
|
321
|
+
captureResponses: true
|
|
322
|
+
});
|
|
323
|
+
// Record for specified duration
|
|
324
|
+
const duration = args.recordingDuration || 5000;
|
|
325
|
+
await new Promise(resolve => setTimeout(resolve, duration));
|
|
326
|
+
// Stop recording
|
|
327
|
+
await networkRecorder.stopRecording();
|
|
328
|
+
// Get redirect information
|
|
329
|
+
const finalUrls = await requestChainTracer.getFinalUrls();
|
|
330
|
+
let redirectChains = {};
|
|
331
|
+
if (args.targetUrl) {
|
|
332
|
+
const chainForTarget = await requestChainTracer.traceRedirects(args.targetUrl);
|
|
333
|
+
redirectChains[args.targetUrl] = chainForTarget;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// Get redirect chains for all URLs
|
|
337
|
+
for (const [originalUrl] of Object.entries(finalUrls)) {
|
|
338
|
+
const chain = await requestChainTracer.traceRedirects(originalUrl);
|
|
339
|
+
if (chain.length > 1) {
|
|
340
|
+
redirectChains[originalUrl] = chain;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
content: {
|
|
346
|
+
redirectChains,
|
|
347
|
+
finalUrls
|
|
348
|
+
},
|
|
349
|
+
isError: false
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
throw new Error(`URL redirect trace failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
354
|
+
}
|
|
355
|
+
}, 'handleURLRedirectTrace');
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
// Helper function to deduplicate video sources
|
|
359
|
+
function deduplicateSources(sources) {
|
|
360
|
+
const seen = new Set();
|
|
361
|
+
const unique = [];
|
|
362
|
+
for (const source of sources) {
|
|
363
|
+
// Create a key based on URL and format
|
|
364
|
+
const key = `${source.url}|${source.format}`;
|
|
365
|
+
if (!seen.has(key)) {
|
|
366
|
+
seen.add(key);
|
|
367
|
+
unique.push(source);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return unique;
|
|
371
|
+
}
|
|
372
|
+
// Export all handlers
|
|
373
|
+
export { withVideoExtractionWorkflowValidation };
|
package/dist/index.js
CHANGED
|
@@ -43,6 +43,8 @@ import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler }
|
|
|
43
43
|
import { handleFullPageScreenshot, handleElementScreenshot, handlePDFGeneration, handleVideoRecording, handleVisualComparison } from './handlers/visual-tools-handlers.js';
|
|
44
44
|
// Import API integration handlers
|
|
45
45
|
import { handleRESTAPIEndpointFinder, handleWebhookSupport, handleAllWebsiteAPIFinder } from './handlers/api-integration-handlers.js';
|
|
46
|
+
// Import video extraction handlers
|
|
47
|
+
import { handleHtmlElementsExtraction, handleNetworkVideoExtraction, handleVideoSelectorGeneration, handleComprehensiveVideoExtraction, handleURLRedirectTrace } from './handlers/video-extraction-handlers.js';
|
|
46
48
|
console.error('🔍 [DEBUG] All modules loaded successfully');
|
|
47
49
|
console.error(`🔍 [DEBUG] Server info: ${JSON.stringify(SERVER_INFO)}`);
|
|
48
50
|
console.error(`🔍 [DEBUG] Available tools: ${TOOLS.length} tools loaded`);
|
|
@@ -233,6 +235,17 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
233
235
|
return await handleWebhookSupport(args);
|
|
234
236
|
case TOOL_NAMES.ALL_WEBSITE_API_FINDER:
|
|
235
237
|
return await handleAllWebsiteAPIFinder(args);
|
|
238
|
+
// Video Extraction Tools
|
|
239
|
+
case TOOL_NAMES.HTML_ELEMENTS_EXTRACTION:
|
|
240
|
+
return await handleHtmlElementsExtraction(args);
|
|
241
|
+
case TOOL_NAMES.NETWORK_VIDEO_EXTRACTION:
|
|
242
|
+
return await handleNetworkVideoExtraction(args);
|
|
243
|
+
case TOOL_NAMES.VIDEO_SELECTOR_GENERATION:
|
|
244
|
+
return await handleVideoSelectorGeneration(args);
|
|
245
|
+
case TOOL_NAMES.COMPREHENSIVE_VIDEO_EXTRACTION:
|
|
246
|
+
return await handleComprehensiveVideoExtraction(args);
|
|
247
|
+
case TOOL_NAMES.URL_REDIRECT_TRACE:
|
|
248
|
+
return await handleURLRedirectTrace(args);
|
|
236
249
|
default:
|
|
237
250
|
throw new Error(`Unknown tool: ${name}`);
|
|
238
251
|
}
|
package/dist/tool-definitions.js
CHANGED
|
@@ -581,6 +581,138 @@ export const TOOLS = [
|
|
|
581
581
|
required: ['text'],
|
|
582
582
|
},
|
|
583
583
|
},
|
|
584
|
+
// Video Extraction Tools
|
|
585
|
+
{
|
|
586
|
+
name: 'html_elements_extraction',
|
|
587
|
+
description: 'Extract video sources from HTML elements (video tags, iframes, embeds, meta tags, data attributes)',
|
|
588
|
+
inputSchema: {
|
|
589
|
+
type: 'object',
|
|
590
|
+
properties: {
|
|
591
|
+
extractVideoTags: {
|
|
592
|
+
type: 'boolean',
|
|
593
|
+
description: 'Extract sources from <video> and <source> tags',
|
|
594
|
+
default: true
|
|
595
|
+
},
|
|
596
|
+
extractIframes: {
|
|
597
|
+
type: 'boolean',
|
|
598
|
+
description: 'Extract sources from <iframe> elements',
|
|
599
|
+
default: true
|
|
600
|
+
},
|
|
601
|
+
extractEmbeds: {
|
|
602
|
+
type: 'boolean',
|
|
603
|
+
description: 'Extract sources from <embed> and <object> elements',
|
|
604
|
+
default: true
|
|
605
|
+
},
|
|
606
|
+
extractMetaTags: {
|
|
607
|
+
type: 'boolean',
|
|
608
|
+
description: 'Extract sources from Open Graph and Twitter Card meta tags',
|
|
609
|
+
default: true
|
|
610
|
+
},
|
|
611
|
+
extractDataAttributes: {
|
|
612
|
+
type: 'boolean',
|
|
613
|
+
description: 'Extract sources from data-* attributes',
|
|
614
|
+
default: true
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
name: 'network_video_extraction',
|
|
621
|
+
description: 'Extract video sources from network requests and responses',
|
|
622
|
+
inputSchema: {
|
|
623
|
+
type: 'object',
|
|
624
|
+
properties: {
|
|
625
|
+
interceptRequests: {
|
|
626
|
+
type: 'boolean',
|
|
627
|
+
description: 'Intercept and analyze network requests',
|
|
628
|
+
default: false
|
|
629
|
+
},
|
|
630
|
+
captureResponses: {
|
|
631
|
+
type: 'boolean',
|
|
632
|
+
description: 'Capture and analyze network responses',
|
|
633
|
+
default: true
|
|
634
|
+
},
|
|
635
|
+
filterResourceTypes: {
|
|
636
|
+
type: 'array',
|
|
637
|
+
description: 'Filter by resource types (xhr, fetch, media, etc.)',
|
|
638
|
+
items: { type: 'string' }
|
|
639
|
+
},
|
|
640
|
+
maxRecords: {
|
|
641
|
+
type: 'number',
|
|
642
|
+
description: 'Maximum number of network requests to record',
|
|
643
|
+
default: 1000
|
|
644
|
+
},
|
|
645
|
+
recordingDuration: {
|
|
646
|
+
type: 'number',
|
|
647
|
+
description: 'Duration to record network traffic (ms)',
|
|
648
|
+
default: 10000
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
name: 'video_selector_generation',
|
|
655
|
+
description: 'Generate CSS selectors for video-related elements on the page',
|
|
656
|
+
inputSchema: {
|
|
657
|
+
type: 'object',
|
|
658
|
+
properties: {}
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
name: 'comprehensive_video_extraction',
|
|
663
|
+
description: 'Extract video sources using all available strategies (DOM + Network)',
|
|
664
|
+
inputSchema: {
|
|
665
|
+
type: 'object',
|
|
666
|
+
properties: {
|
|
667
|
+
enableDOMAnalysis: {
|
|
668
|
+
type: 'boolean',
|
|
669
|
+
description: 'Enable DOM-based video extraction',
|
|
670
|
+
default: true
|
|
671
|
+
},
|
|
672
|
+
enableNetworkRecording: {
|
|
673
|
+
type: 'boolean',
|
|
674
|
+
description: 'Enable network-based video extraction',
|
|
675
|
+
default: true
|
|
676
|
+
},
|
|
677
|
+
recordingDuration: {
|
|
678
|
+
type: 'number',
|
|
679
|
+
description: 'Duration to record network traffic (ms)',
|
|
680
|
+
default: 10000
|
|
681
|
+
},
|
|
682
|
+
maxSources: {
|
|
683
|
+
type: 'number',
|
|
684
|
+
description: 'Maximum number of video sources to return',
|
|
685
|
+
default: 50
|
|
686
|
+
},
|
|
687
|
+
filterFormats: {
|
|
688
|
+
type: 'array',
|
|
689
|
+
description: 'Filter results by video format',
|
|
690
|
+
items: {
|
|
691
|
+
type: 'string',
|
|
692
|
+
enum: ['mp4', 'webm', 'avi', 'mkv', 'hls', 'dash', 'ts', 'flv', 'blob']
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: 'url_redirect_trace',
|
|
700
|
+
description: 'Trace URL redirects and get final destinations',
|
|
701
|
+
inputSchema: {
|
|
702
|
+
type: 'object',
|
|
703
|
+
properties: {
|
|
704
|
+
targetUrl: {
|
|
705
|
+
type: 'string',
|
|
706
|
+
description: 'Specific URL to trace redirects for'
|
|
707
|
+
},
|
|
708
|
+
recordingDuration: {
|
|
709
|
+
type: 'number',
|
|
710
|
+
description: 'Duration to record network traffic (ms)',
|
|
711
|
+
default: 5000
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
},
|
|
584
716
|
// Data Validation Tools
|
|
585
717
|
{
|
|
586
718
|
name: 'schema_validator',
|
|
@@ -1051,6 +1183,12 @@ export const TOOL_NAMES = {
|
|
|
1051
1183
|
REST_API_ENDPOINT_FINDER: 'rest_api_endpoint_finder',
|
|
1052
1184
|
WEBHOOK_SUPPORT: 'webhook_support',
|
|
1053
1185
|
ALL_WEBSITE_API_FINDER: 'all_website_api_finder',
|
|
1186
|
+
// Video Extraction Tools
|
|
1187
|
+
HTML_ELEMENTS_EXTRACTION: 'html_elements_extraction',
|
|
1188
|
+
NETWORK_VIDEO_EXTRACTION: 'network_video_extraction',
|
|
1189
|
+
VIDEO_SELECTOR_GENERATION: 'video_selector_generation',
|
|
1190
|
+
COMPREHENSIVE_VIDEO_EXTRACTION: 'comprehensive_video_extraction',
|
|
1191
|
+
URL_REDIRECT_TRACE: 'url_redirect_trace',
|
|
1054
1192
|
};
|
|
1055
1193
|
// Tool categories for organization
|
|
1056
1194
|
export const TOOL_CATEGORIES = {
|