brave-real-browser-mcp-server 2.14.15 → 2.15.1
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/README.md +10 -17
- package/dist/handlers/advanced-video-media-handlers.js +1 -28
- package/dist/index.js +1 -28
- package/dist/mcp-server.js +1 -4
- package/dist/tool-definitions.js +0 -83
- package/package.json +2 -2
- package/scripts/setup-brave.cjs +171 -0
package/README.md
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|

|
|
9
|
-

|
|
10
10
|

|
|
11
11
|

|
|
12
12
|
|
|
13
|
-
**सभी AI IDEs के लिए Universal MCP Server |
|
|
13
|
+
**सभी AI IDEs के लिए Universal MCP Server | 78+ Tools | Browser Automation | Web Scraping | CAPTCHA Solving**
|
|
14
14
|
|
|
15
|
-
[Installation](#-installation) | [Quick Start](#-quick-start) | [Qoder AI Setup](#-qoder-ai---complete-integration-guide) | [Tools](#-available-tools-
|
|
15
|
+
[Installation](#-installation) | [Quick Start](#-quick-start) | [Qoder AI Setup](#-qoder-ai---complete-integration-guide) | [Tools](#-available-tools-78) | [IDE Configurations](#-ide-configurations)
|
|
16
16
|
|
|
17
17
|
</div>
|
|
18
18
|
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
**Brave Real Browser MCP Server** एक powerful automation tool है जो:
|
|
24
24
|
|
|
25
25
|
- ✅ **20+ AI IDEs में काम करता है** (Antigravity, Warp AI, Zed, Cursor, Claude, Windsurf, Cline, Qoder AI, etc.)
|
|
26
|
-
- ✅ **
|
|
26
|
+
- ✅ **78+ Automation Tools** - Browser control, scraping, CAPTCHA solving, video extraction
|
|
27
27
|
- ✅ **MCP Protocol (STDIO)** - Fast and secure local communication
|
|
28
28
|
- ✅ **Auto-Detection** - Automatically detects your IDE
|
|
29
29
|
- ✅ **Real Brave Browser** - Anti-detection features, bypass Cloudflare
|
|
@@ -189,7 +189,7 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
189
189
|
|
|
190
190
|
---
|
|
191
191
|
|
|
192
|
-
## 🛠️ Available Tools (
|
|
192
|
+
## 🛠️ Available Tools (78)
|
|
193
193
|
|
|
194
194
|
### 🌐 Browser Management (2 tools)
|
|
195
195
|
|
|
@@ -262,24 +262,18 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
262
262
|
| Tool | Description |
|
|
263
263
|
| ------------------------------- | ---------------------------------------- |
|
|
264
264
|
| `video_link_finder` | Find video URLs |
|
|
265
|
-
| `video_download_page` | Navigate to video download page |
|
|
266
265
|
| `video_download_button` | Find video download buttons |
|
|
267
266
|
| `video_play_push_source` | Get video play sources |
|
|
268
267
|
| `video_play_button_click` | Click video play button |
|
|
269
|
-
| `url_redirect_trace_endpoints` | Trace URL redirects |
|
|
270
|
-
| `network_recording_finder` | Find network recordings |
|
|
271
|
-
| `network_recording_extractors` | Extract network data |
|
|
272
|
-
| `video_links_finders` | Multiple video link finders |
|
|
273
|
-
| `videos_selectors` | Video element selectors |
|
|
274
|
-
| `link_process_extracts` | Process and extract links |
|
|
275
|
-
| `video_link_finders_extracts` | Advanced video link extraction |
|
|
276
|
-
| `video_download_button_finders` | Find all download buttons |
|
|
277
268
|
| `advanced_video_extraction` | Advanced video extraction with ad-bypass |
|
|
278
269
|
| `image_extractor_advanced` | Advanced image extraction |
|
|
279
270
|
| `video_source_extractor` | Extract video source URLs |
|
|
280
271
|
| `video_player_extractor` | Extract video player info |
|
|
281
272
|
| `video_player_hoster_finder` | Find video hosting platform |
|
|
282
273
|
| `original_video_hoster_finder` | Find original video source |
|
|
274
|
+
| `stream_detector` | Detect HLS/DASH streams |
|
|
275
|
+
| `redirect_tracer` | Trace URL redirects |
|
|
276
|
+
| `video_download_link_finder` | Find direct download links |
|
|
283
277
|
|
|
284
278
|
### 🔐 CAPTCHA & Security (4 tools)
|
|
285
279
|
|
|
@@ -381,12 +375,11 @@ npm install -g brave-real-browser-mcp-server@latest
|
|
|
381
375
|
| `deobfuscate_js` | Deobfuscate JavaScript |
|
|
382
376
|
| `multi_layer_redirect_trace` | Trace multi-layer redirects |
|
|
383
377
|
| `ad_protection_detector` | Detect ad protection |
|
|
384
|
-
| `url_redirect_tracer` | Trace URL redirects |
|
|
385
378
|
|
|
386
379
|
|
|
387
380
|
## 🔧 Environment Variables
|
|
388
381
|
|
|
389
|
-
|
|
382
|
+
|
|
390
383
|
|
|
391
384
|
You can configure the server using the local `.env` file directly.
|
|
392
385
|
|
|
@@ -428,6 +421,6 @@ MIT License - See LICENSE file for details.
|
|
|
428
421
|
|
|
429
422
|
<div align="center">
|
|
430
423
|
|
|
431
|
-
**🌟
|
|
424
|
+
**🌟 78 Tools | 15+ AI IDEs | MCP Protocol | Universal Support 🌟**
|
|
432
425
|
|
|
433
426
|
**Made with ❤️ for the AI Development Community**
|
|
@@ -105,7 +105,7 @@ export async function handleVideoDownloadLinkFinder(args) {
|
|
|
105
105
|
// --- Implementation of missing "Ghost" handlers required by index.ts ---
|
|
106
106
|
// Aliases or specific implementations
|
|
107
107
|
export const handleVideoLinkFinder = handleVideoDownloadLinkFinder;
|
|
108
|
-
export async function
|
|
108
|
+
export async function handleVideoDownloadButton(args) {
|
|
109
109
|
// Basic implementation trying to find "Download" buttons contextually
|
|
110
110
|
const page = getPageInstance();
|
|
111
111
|
if (!page)
|
|
@@ -119,9 +119,6 @@ export async function handleVideoDownloadPage(args) {
|
|
|
119
119
|
});
|
|
120
120
|
return { content: [{ type: 'text', text: JSON.stringify(downloadProbability, null, 2) }] };
|
|
121
121
|
}
|
|
122
|
-
export async function handleVideoDownloadButton(args) {
|
|
123
|
-
return handleVideoDownloadPage(args);
|
|
124
|
-
}
|
|
125
122
|
export async function handleVideoPlayPushSource(args) {
|
|
126
123
|
return { content: [{ type: 'text', text: "Video Play Push Source detected (Simulated)" }] };
|
|
127
124
|
}
|
|
@@ -140,27 +137,3 @@ export async function handleVideoPlayButtonClick(args) {
|
|
|
140
137
|
});
|
|
141
138
|
return { content: [{ type: 'text', text: clicked ? "Clicked Play Button" : "No Play Button Found" }] };
|
|
142
139
|
}
|
|
143
|
-
export async function handleUrlRedirectTraceEndpoints(args) {
|
|
144
|
-
return handleRedirectTracer(args);
|
|
145
|
-
}
|
|
146
|
-
export async function handleNetworkRecordingFinder(args) {
|
|
147
|
-
return handleStreamDetector(args);
|
|
148
|
-
}
|
|
149
|
-
export async function handleNetworkRecordingExtractors(args) {
|
|
150
|
-
return handleStreamDetector(args);
|
|
151
|
-
}
|
|
152
|
-
export async function handleVideoLinksFinders(args) {
|
|
153
|
-
return handleVideoDownloadLinkFinder(args);
|
|
154
|
-
}
|
|
155
|
-
export async function handleVideosSelectors(args) {
|
|
156
|
-
return handleVideoSourceExtractor(args);
|
|
157
|
-
}
|
|
158
|
-
export async function handleLinkProcessExtracts(args) {
|
|
159
|
-
return { content: [{ type: 'text', text: "Link Process Extracts (Stub)" }] };
|
|
160
|
-
}
|
|
161
|
-
export async function handleVideoLinkFindersExtracts(args) {
|
|
162
|
-
return handleVideoDownloadLinkFinder(args);
|
|
163
|
-
}
|
|
164
|
-
export async function handleVideoDownloadButtonFinders(args) {
|
|
165
|
-
return handleVideoDownloadPage(args);
|
|
166
|
-
}
|
package/dist/index.js
CHANGED
|
@@ -50,7 +50,7 @@ import { handleShadowDOMExtractor, handleCookieManager, handleFormAutoFill, hand
|
|
|
50
50
|
// Import monitoring & reporting handlers
|
|
51
51
|
import { handleProgressTracker, handleDataQualityMetrics, } from "./handlers/monitoring-reporting-handlers.js";
|
|
52
52
|
// Import advanced video & media handlers
|
|
53
|
-
import { handleVideoLinkFinder,
|
|
53
|
+
import { handleVideoLinkFinder, handleVideoDownloadButton, handleVideoPlayPushSource, handleVideoPlayButtonClick, } from "./handlers/advanced-video-media-handlers.js";
|
|
54
54
|
// Import advanced extraction handlers (Ad-bypass & Obfuscation)
|
|
55
55
|
import { handleAdvancedVideoExtraction, handleDeobfuscateJS, handleMultiLayerRedirectTrace, handleAdProtectionDetector, } from "./handlers/advanced-extraction-handlers.js";
|
|
56
56
|
console.error("🔍 [DEBUG] All modules loaded successfully");
|
|
@@ -315,9 +315,6 @@ export async function executeToolByName(name, args) {
|
|
|
315
315
|
case "video_link_finder":
|
|
316
316
|
result = await handleVideoLinkFinder(args || {});
|
|
317
317
|
break;
|
|
318
|
-
case "video_download_page":
|
|
319
|
-
result = await handleVideoDownloadPage(args || {});
|
|
320
|
-
break;
|
|
321
318
|
case "video_download_button":
|
|
322
319
|
result = await handleVideoDownloadButton(args);
|
|
323
320
|
break;
|
|
@@ -327,30 +324,6 @@ export async function executeToolByName(name, args) {
|
|
|
327
324
|
case "video_play_button_click":
|
|
328
325
|
result = await handleVideoPlayButtonClick(args || {});
|
|
329
326
|
break;
|
|
330
|
-
case "url_redirect_trace_endpoints":
|
|
331
|
-
result = await handleUrlRedirectTraceEndpoints(args);
|
|
332
|
-
break;
|
|
333
|
-
case "network_recording_finder":
|
|
334
|
-
result = await handleNetworkRecordingFinder(args || {});
|
|
335
|
-
break;
|
|
336
|
-
case "network_recording_extractors":
|
|
337
|
-
result = await handleNetworkRecordingExtractors(args || {});
|
|
338
|
-
break;
|
|
339
|
-
case "video_links_finders":
|
|
340
|
-
result = await handleVideoLinksFinders(args || {});
|
|
341
|
-
break;
|
|
342
|
-
case "videos_selectors":
|
|
343
|
-
result = await handleVideosSelectors(args || {});
|
|
344
|
-
break;
|
|
345
|
-
case "link_process_extracts":
|
|
346
|
-
result = await handleLinkProcessExtracts(args || {});
|
|
347
|
-
break;
|
|
348
|
-
case "video_link_finders_extracts":
|
|
349
|
-
result = await handleVideoLinkFindersExtracts(args || {});
|
|
350
|
-
break;
|
|
351
|
-
case "video_download_button_finders":
|
|
352
|
-
result = await handleVideoDownloadButtonFinders(args || {});
|
|
353
|
-
break;
|
|
354
327
|
// Advanced Extraction Tools (Ad-Bypass & Obfuscation)
|
|
355
328
|
case "advanced_video_extraction":
|
|
356
329
|
result = await handleAdvancedVideoExtraction(args || {});
|
package/dist/mcp-server.js
CHANGED
|
@@ -17,7 +17,7 @@ import { handleHtmlToText, handleDuplicateRemover } from './handlers/data-transf
|
|
|
17
17
|
import { handleConsistencyChecker } from './handlers/data-quality-handlers.js';
|
|
18
18
|
import { handleSmartSelectorGenerator, handleContentClassification, handleSentimentAnalysis, handleSummaryGenerator, handleTranslationSupport } from './handlers/ai-powered-handlers.js';
|
|
19
19
|
import { handleKeywordSearch, handleRegexPatternMatcher, handleXPathSupport, handleAdvancedCSSSelectors, handleVisualElementFinder } from './handlers/search-filter-handlers.js';
|
|
20
|
-
import { handleVideoSourceExtractor, handleVideoPlayerFinder, handleStreamDetector, handleRedirectTracer
|
|
20
|
+
import { handleVideoSourceExtractor, handleVideoPlayerFinder, handleStreamDetector, handleRedirectTracer } from './handlers/advanced-video-media-handlers.js';
|
|
21
21
|
import { handleOCREngine, handleAudioCaptchaSolver, handlePuzzleCaptchaHandler } from './handlers/captcha-handlers.js';
|
|
22
22
|
import { handleAdvancedVideoExtraction, handleDeobfuscateJS, handleMultiLayerRedirectTrace, handleAdProtectionDetector } from './handlers/advanced-extraction-handlers.js';
|
|
23
23
|
export async function createMcpServer() {
|
|
@@ -209,9 +209,6 @@ export async function createMcpServer() {
|
|
|
209
209
|
case TOOL_NAMES.REDIRECT_TRACER:
|
|
210
210
|
result = await handleRedirectTracer(args);
|
|
211
211
|
break;
|
|
212
|
-
case TOOL_NAMES.VIDEO_DOWNLOAD_LINK_FINDER:
|
|
213
|
-
result = await handleVideoDownloadLinkFinder(args);
|
|
214
|
-
break;
|
|
215
212
|
// Phase 4: Captcha & Security
|
|
216
213
|
case TOOL_NAMES.OCR_ENGINE:
|
|
217
214
|
result = await handleOCREngine(args);
|
package/dist/tool-definitions.js
CHANGED
|
@@ -1003,14 +1003,6 @@ export const TOOLS = [
|
|
|
1003
1003
|
},
|
|
1004
1004
|
},
|
|
1005
1005
|
},
|
|
1006
|
-
{
|
|
1007
|
-
name: 'video_download_page',
|
|
1008
|
-
description: 'Detect and analyze video download pages',
|
|
1009
|
-
inputSchema: {
|
|
1010
|
-
type: 'object',
|
|
1011
|
-
properties: {},
|
|
1012
|
-
},
|
|
1013
|
-
},
|
|
1014
1006
|
{
|
|
1015
1007
|
name: 'video_download_button',
|
|
1016
1008
|
description: 'Find and interact with video download buttons',
|
|
@@ -1040,80 +1032,6 @@ export const TOOLS = [
|
|
|
1040
1032
|
},
|
|
1041
1033
|
},
|
|
1042
1034
|
},
|
|
1043
|
-
{
|
|
1044
|
-
name: 'url_redirect_trace_endpoints',
|
|
1045
|
-
description: 'Trace all URL redirect endpoints',
|
|
1046
|
-
inputSchema: {
|
|
1047
|
-
type: 'object',
|
|
1048
|
-
properties: {
|
|
1049
|
-
url: { type: 'string' },
|
|
1050
|
-
},
|
|
1051
|
-
required: ['url'],
|
|
1052
|
-
},
|
|
1053
|
-
},
|
|
1054
|
-
{
|
|
1055
|
-
name: 'network_recording_finder',
|
|
1056
|
-
description: 'Find and analyze network recordings',
|
|
1057
|
-
inputSchema: {
|
|
1058
|
-
type: 'object',
|
|
1059
|
-
properties: {
|
|
1060
|
-
duration: { type: 'number', default: 10000 },
|
|
1061
|
-
filterType: { type: 'string', enum: ['video', 'audio', 'media'], default: 'video' },
|
|
1062
|
-
},
|
|
1063
|
-
},
|
|
1064
|
-
},
|
|
1065
|
-
{
|
|
1066
|
-
name: 'network_recording_extractors',
|
|
1067
|
-
description: 'Extract data from network recordings',
|
|
1068
|
-
inputSchema: {
|
|
1069
|
-
type: 'object',
|
|
1070
|
-
properties: {
|
|
1071
|
-
duration: { type: 'number', default: 10000 },
|
|
1072
|
-
},
|
|
1073
|
-
},
|
|
1074
|
-
},
|
|
1075
|
-
{
|
|
1076
|
-
name: 'video_links_finders',
|
|
1077
|
-
description: 'Advanced video link detection',
|
|
1078
|
-
inputSchema: {
|
|
1079
|
-
type: 'object',
|
|
1080
|
-
properties: {},
|
|
1081
|
-
},
|
|
1082
|
-
},
|
|
1083
|
-
{
|
|
1084
|
-
name: 'videos_selectors',
|
|
1085
|
-
description: 'Get all video-related selectors',
|
|
1086
|
-
inputSchema: {
|
|
1087
|
-
type: 'object',
|
|
1088
|
-
properties: {},
|
|
1089
|
-
},
|
|
1090
|
-
},
|
|
1091
|
-
{
|
|
1092
|
-
name: 'link_process_extracts',
|
|
1093
|
-
description: 'Process and extract links with categorization',
|
|
1094
|
-
inputSchema: {
|
|
1095
|
-
type: 'object',
|
|
1096
|
-
properties: {
|
|
1097
|
-
processType: { type: 'string', enum: ['all', 'video', 'download', 'external'], default: 'all' },
|
|
1098
|
-
},
|
|
1099
|
-
},
|
|
1100
|
-
},
|
|
1101
|
-
{
|
|
1102
|
-
name: 'video_link_finders_extracts',
|
|
1103
|
-
description: 'Extract video links with complete metadata',
|
|
1104
|
-
inputSchema: {
|
|
1105
|
-
type: 'object',
|
|
1106
|
-
properties: {},
|
|
1107
|
-
},
|
|
1108
|
-
},
|
|
1109
|
-
{
|
|
1110
|
-
name: 'video_download_button_finders',
|
|
1111
|
-
description: 'Find all video download buttons on page',
|
|
1112
|
-
inputSchema: {
|
|
1113
|
-
type: 'object',
|
|
1114
|
-
properties: {},
|
|
1115
|
-
},
|
|
1116
|
-
},
|
|
1117
1035
|
// Advanced Extraction Tools (Ad-Bypass & Obfuscation)
|
|
1118
1036
|
{
|
|
1119
1037
|
name: 'advanced_video_extraction',
|
|
@@ -1314,7 +1232,6 @@ export const TOOL_NAMES = {
|
|
|
1314
1232
|
VIDEO_PLAYER_FINDER: 'video_player_finder',
|
|
1315
1233
|
STREAM_DETECTOR: 'stream_detector',
|
|
1316
1234
|
REDIRECT_TRACER: 'redirect_tracer',
|
|
1317
|
-
VIDEO_DOWNLOAD_LINK_FINDER: 'video_download_link_finder',
|
|
1318
1235
|
// Search & Filter Tools
|
|
1319
1236
|
KEYWORD_SEARCH: 'keyword_search',
|
|
1320
1237
|
REGEX_PATTERN_MATCHER: 'regex_pattern_matcher',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.1",
|
|
4
4
|
"description": "Universal AI IDE MCP Server - Auto-detects and supports all AI IDEs (Claude Desktop, Cursor, Windsurf, Cline, Zed, VSCode, Qoder AI, etc.) with Brave browser automation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"test:brave:cleanup": "taskkill /F /IM brave.exe || pkill -f brave || true"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
38
38
|
"@types/turndown": "^5.0.6",
|
|
39
39
|
"ajv": "^8.12.0",
|
|
40
40
|
"axios": "^1.6.5",
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const { execSync, exec } = require('child_process');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
|
|
7
|
+
// Colors for console output
|
|
8
|
+
const colors = {
|
|
9
|
+
reset: "\x1b[0m",
|
|
10
|
+
bright: "\x1b[1m",
|
|
11
|
+
green: "\x1b[32m",
|
|
12
|
+
yellow: "\x1b[33m",
|
|
13
|
+
red: "\x1b[31m",
|
|
14
|
+
cyan: "\x1b[36m"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function log(message, type = 'info') {
|
|
18
|
+
const timestamp = new Date().toISOString();
|
|
19
|
+
let color = colors.reset;
|
|
20
|
+
if (type === 'success') color = colors.green;
|
|
21
|
+
if (type === 'warn') color = colors.yellow;
|
|
22
|
+
if (type === 'error') color = colors.red;
|
|
23
|
+
if (type === 'info') color = colors.cyan;
|
|
24
|
+
console.log(`${color}[${type.toUpperCase()}] ${message}${colors.reset}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const platform = os.platform();
|
|
28
|
+
|
|
29
|
+
// Define standard paths including the user's specific request
|
|
30
|
+
const bravePaths = {
|
|
31
|
+
win32: [
|
|
32
|
+
'C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe', // User's requested primary path
|
|
33
|
+
'C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe',
|
|
34
|
+
path.join(os.homedir(), 'AppData', 'Local', 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe')
|
|
35
|
+
],
|
|
36
|
+
darwin: [
|
|
37
|
+
'/Applications/Brave Browser.app/Contents/MacOS/Brave Browser'
|
|
38
|
+
],
|
|
39
|
+
linux: [
|
|
40
|
+
'/usr/bin/brave-browser',
|
|
41
|
+
'/usr/bin/brave',
|
|
42
|
+
'/snap/bin/brave'
|
|
43
|
+
]
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
async function checkBraveInstallation() {
|
|
47
|
+
log("Checking for Brave Browser installation...", 'info');
|
|
48
|
+
|
|
49
|
+
let foundPath = null;
|
|
50
|
+
const pathsToCheck = bravePaths[platform] || [];
|
|
51
|
+
|
|
52
|
+
for (const p of pathsToCheck) {
|
|
53
|
+
if (fs.existsSync(p)) {
|
|
54
|
+
foundPath = p;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (foundPath) {
|
|
60
|
+
log(`Brave Browser found at: ${foundPath}`, 'success');
|
|
61
|
+
updateEnvFile(foundPath);
|
|
62
|
+
return true;
|
|
63
|
+
} else {
|
|
64
|
+
log("Brave Browser not found in standard locations.", 'warn');
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function updateEnvFile(bravePath) {
|
|
70
|
+
const envPath = path.join(__dirname, '..', '.env');
|
|
71
|
+
try {
|
|
72
|
+
let envContent = '';
|
|
73
|
+
if (fs.existsSync(envPath)) {
|
|
74
|
+
envContent = fs.readFileSync(envPath, 'utf8');
|
|
75
|
+
} else {
|
|
76
|
+
// Create from example if possible, or just start empty
|
|
77
|
+
const examplePath = path.join(__dirname, '..', '.env.example');
|
|
78
|
+
if(fs.existsSync(examplePath)) {
|
|
79
|
+
envContent = fs.readFileSync(examplePath, 'utf8');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check if BRAVE_PATH is already set
|
|
84
|
+
if (envContent.includes('BRAVE_PATH=')) {
|
|
85
|
+
// Replace existing
|
|
86
|
+
const newContent = envContent.replace(/^BRAVE_PATH=.*$/m, `BRAVE_PATH=${bravePath}`);
|
|
87
|
+
if (newContent !== envContent) {
|
|
88
|
+
fs.writeFileSync(envPath, newContent);
|
|
89
|
+
log("Updated .env with detected Brave path.", 'success');
|
|
90
|
+
} else {
|
|
91
|
+
log(".env already has a BRAVE_PATH set (or format differs).", 'info');
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
// Append
|
|
95
|
+
fs.appendFileSync(envPath, `\nBRAVE_PATH=${bravePath}\n`);
|
|
96
|
+
log("Appended BRAVE_PATH to .env.", 'success');
|
|
97
|
+
}
|
|
98
|
+
} catch (err) {
|
|
99
|
+
log(`Failed to update .env: ${err.message}`, 'error');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function installBrave() {
|
|
104
|
+
log("Attempting to install Brave Browser...", 'info');
|
|
105
|
+
|
|
106
|
+
if (platform === 'win32') {
|
|
107
|
+
const installerUrl = 'https://laptop-updates.brave.com/latest/winx64'; // Standard stub installer
|
|
108
|
+
const installerPath = path.join(os.tmpdir(), 'BraveBrowserSetup.exe');
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await downloadFile(installerUrl, installerPath);
|
|
112
|
+
log(`Installer downloaded to ${installerPath}`, 'success');
|
|
113
|
+
log("Running installer... Please follow the prompts if any appear.", 'info');
|
|
114
|
+
|
|
115
|
+
// Run installer
|
|
116
|
+
// /silent /install are common flags for Chromium based browsers.
|
|
117
|
+
// But we use start to let it run interactively if needed, or silent if possible.
|
|
118
|
+
// The standard stub installer usually just runs.
|
|
119
|
+
exec(`"${installerPath}"`, (error, stdout, stderr) => {
|
|
120
|
+
if (error) {
|
|
121
|
+
log(`Installer execution failed: ${error.message}`, 'error');
|
|
122
|
+
} else {
|
|
123
|
+
log("Installer started. Please complete the installation.", 'success');
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
} catch (err) {
|
|
128
|
+
log(`Failed to download/run installer: ${err.message}`, 'error');
|
|
129
|
+
log("Please install Brave manually from https://brave.com/download/", 'warn');
|
|
130
|
+
}
|
|
131
|
+
} else if (platform === 'darwin') {
|
|
132
|
+
log("Automatic installation on macOS is complex. Opening download page...", 'info');
|
|
133
|
+
exec('open https://brave.com/download/');
|
|
134
|
+
} else if (platform === 'linux') {
|
|
135
|
+
log("Please install Brave using your package manager (apt, dnf, snap, etc.).", 'info');
|
|
136
|
+
console.log("Visit: https://brave.com/linux/");
|
|
137
|
+
} else {
|
|
138
|
+
log(`Unsupported platform for auto-install: ${platform}`, 'error');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function downloadFile(url, dest) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const file = fs.createWriteStream(dest);
|
|
145
|
+
https.get(url, (response) => {
|
|
146
|
+
if (response.statusCode !== 200) {
|
|
147
|
+
reject(new Error(`Failed to download: Status Code ${response.statusCode}`));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
response.pipe(file);
|
|
151
|
+
file.on('finish', () => {
|
|
152
|
+
file.close(resolve);
|
|
153
|
+
});
|
|
154
|
+
}).on('error', (err) => {
|
|
155
|
+
fs.unlink(dest, () => {}); // Delete the file async. (But we don't check result)
|
|
156
|
+
reject(err);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function main() {
|
|
162
|
+
const isInstalled = await checkBraveInstallation();
|
|
163
|
+
if (!isInstalled) {
|
|
164
|
+
await installBrave();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
main().catch(err => {
|
|
169
|
+
console.error("Setup script failed:", err);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
});
|