brave-real-browser-mcp-server 2.25.0 → 2.26.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.
@@ -2998,17 +2998,62 @@ export async function handleWebCrawler(page, args) {
2998
2998
  browserPoolOptions: {
2999
2999
  maxOpenPagesPerBrowser: 1,
3000
3000
  },
3001
- // Pre-navigation hook for rate limiting and proxy
3001
+ // Pre-navigation hook for rate limiting, popup blocking, and movie streaming optimizations
3002
3002
  preNavigationHooks: [
3003
3003
  async (crawlingContext) => {
3004
3004
  await enforceRateLimit();
3005
+ const pg = crawlingContext.page;
3005
3006
  // Set custom user agent if provided
3006
3007
  if (args.userAgent) {
3007
- await crawlingContext.page.setUserAgent(args.userAgent);
3008
+ await pg.setUserAgent(args.userAgent);
3008
3009
  }
3009
3010
  // Set custom headers if provided
3010
3011
  if (args.headers) {
3011
- await crawlingContext.page.setExtraHTTPHeaders(args.headers);
3012
+ await pg.setExtraHTTPHeaders(args.headers);
3013
+ }
3014
+ // Block popups and overlay ads (default: true for movie streaming)
3015
+ if (args.blockPopups !== false) {
3016
+ await pg.evaluateOnNewDocument(() => {
3017
+ // Block window.open popups
3018
+ window.open = () => null;
3019
+ // Block alert, confirm, prompt
3020
+ window.alert = () => { };
3021
+ window.confirm = () => true;
3022
+ window.prompt = () => null;
3023
+ // Block popup via createElement
3024
+ const origCreate = document.createElement.bind(document);
3025
+ document.createElement = (tag) => {
3026
+ if (tag.toLowerCase() === 'a' && arguments[1]?.target === '_blank') {
3027
+ return origCreate('span');
3028
+ }
3029
+ return origCreate(tag);
3030
+ };
3031
+ });
3032
+ }
3033
+ // Block overlay ads and floating elements
3034
+ if (args.blockOverlayAds !== false) {
3035
+ await pg.evaluateOnNewDocument(() => {
3036
+ // Remove overlay ads after DOM load
3037
+ const removeOverlays = () => {
3038
+ const selectors = [
3039
+ '[class*="popup"]', '[class*="modal"]', '[class*="overlay"]',
3040
+ '[id*="popup"]', '[id*="modal"]', '[id*="overlay"]',
3041
+ '[class*="ad-"]', '[class*="-ad"]', '[class*="advert"]',
3042
+ '[class*="banner"]', '[class*="sticky"]', '[class*="float"]',
3043
+ 'div[style*="position: fixed"]', 'div[style*="z-index: 9"]',
3044
+ ];
3045
+ selectors.forEach(sel => {
3046
+ document.querySelectorAll(sel).forEach(el => {
3047
+ const style = window.getComputedStyle(el);
3048
+ if (style.position === 'fixed' || style.zIndex > '1000') {
3049
+ el.style.display = 'none';
3050
+ }
3051
+ });
3052
+ });
3053
+ };
3054
+ document.addEventListener('DOMContentLoaded', removeOverlays);
3055
+ setInterval(removeOverlays, 2000);
3056
+ });
3012
3057
  }
3013
3058
  },
3014
3059
  ],
@@ -3051,6 +3096,85 @@ export async function handleWebCrawler(page, args) {
3051
3096
  }
3052
3097
  }
3053
3098
  }
3099
+ // Extract video links (JWPlayer, DooPlayer, iframes, ajax sources)
3100
+ if (args.extractVideoLinks !== false) {
3101
+ result.videoLinks = await crawlerPage.evaluate(() => {
3102
+ const videoLinks = [];
3103
+ const videoPatterns = /\.(m3u8|mp4|mkv|webm|avi|mov|flv|wmv|ts)(\?|$)/i;
3104
+ // 1. JWPlayer detection
3105
+ if (window.jwplayer) {
3106
+ try {
3107
+ const players = document.querySelectorAll('.jwplayer, [id*="jwplayer"]');
3108
+ players.forEach((_, idx) => {
3109
+ try {
3110
+ const player = window.jwplayer(idx);
3111
+ if (player && player.getPlaylistItem) {
3112
+ const item = player.getPlaylistItem();
3113
+ if (item?.file) {
3114
+ videoLinks.push({ url: item.file, type: item.file.includes('.m3u8') ? 'm3u8' : 'mp4', source: 'jwplayer' });
3115
+ }
3116
+ if (item?.sources) {
3117
+ item.sources.forEach((s) => {
3118
+ if (s.file)
3119
+ videoLinks.push({ url: s.file, type: s.type || 'mp4', source: 'jwplayer' });
3120
+ });
3121
+ }
3122
+ }
3123
+ }
3124
+ catch { }
3125
+ });
3126
+ }
3127
+ catch { }
3128
+ }
3129
+ // 2. DooPlayer detection (common in movie sites)
3130
+ if (window.dooPlayer || document.querySelector('[id*="doo"]')) {
3131
+ try {
3132
+ const dooConfig = window.dooPlayer?.config || window.player_config;
3133
+ if (dooConfig?.source) {
3134
+ videoLinks.push({ url: dooConfig.source, type: 'm3u8', source: 'dooplayer' });
3135
+ }
3136
+ }
3137
+ catch { }
3138
+ }
3139
+ // 3. Iframe video sources
3140
+ document.querySelectorAll('iframe').forEach(iframe => {
3141
+ const src = iframe.src || iframe.getAttribute('data-src') || '';
3142
+ if (src && (src.includes('embed') || src.includes('player') || src.includes('stream'))) {
3143
+ videoLinks.push({ url: src, type: 'iframe', source: 'iframe' });
3144
+ }
3145
+ });
3146
+ // 4. Video tags
3147
+ document.querySelectorAll('video source, video').forEach(el => {
3148
+ const src = el.getAttribute('src') || el.src;
3149
+ if (src && videoPatterns.test(src)) {
3150
+ const ext = src.match(videoPatterns)?.[1] || 'mp4';
3151
+ videoLinks.push({ url: src, type: ext, source: 'video-tag' });
3152
+ }
3153
+ });
3154
+ // 5. Hidden links in scripts (ajax pattern)
3155
+ document.querySelectorAll('script:not([src])').forEach(script => {
3156
+ const content = script.textContent || '';
3157
+ // m3u8/mp4 in script
3158
+ const matches = content.match(/https?:\/\/[^\s"'<>]+\.(m3u8|mp4|mkv)[^\s"'<>]*/gi);
3159
+ if (matches) {
3160
+ matches.forEach(url => {
3161
+ const ext = url.match(videoPatterns)?.[1] || 'mp4';
3162
+ videoLinks.push({ url, type: ext, source: 'ajax-script' });
3163
+ });
3164
+ }
3165
+ });
3166
+ // 6. Data attributes with video URLs
3167
+ document.querySelectorAll('[data-file], [data-source], [data-video], [data-stream]').forEach(el => {
3168
+ const url = el.getAttribute('data-file') || el.getAttribute('data-source') ||
3169
+ el.getAttribute('data-video') || el.getAttribute('data-stream');
3170
+ if (url && (videoPatterns.test(url) || url.includes('m3u8'))) {
3171
+ videoLinks.push({ url, type: url.includes('m3u8') ? 'm3u8' : 'mp4', source: 'data-attr' });
3172
+ }
3173
+ });
3174
+ // Deduplicate
3175
+ return [...new Map(videoLinks.map(v => [v.url, v])).values()];
3176
+ });
3177
+ }
3054
3178
  // Follow links if enabled and depth allows
3055
3179
  if (args.followLinks !== false && depth < maxDepth && results.length < maxPages) {
3056
3180
  // Get all links
@@ -623,11 +623,11 @@ export const TOOLS = [
623
623
  },
624
624
  },
625
625
  // ============================================================
626
- // WEB CRAWLER TOOL (Crawlee-inspired)
626
+ // WEB CRAWLER TOOL (Movie Streaming Optimized)
627
627
  // ============================================================
628
628
  {
629
629
  name: 'web_crawler',
630
- description: 'Advanced web crawler with Crawlee-like features: URL queue (breadth/depth-first), proxy rotation, session management, auto-retry, rate limiting, concurrency control, and data extraction. Supports both browser and HTTP modes.',
630
+ description: 'Advanced web crawler optimized for movie downloading and streaming websites. Features: URL queue (breadth/depth-first), proxy rotation, auto-retry, rate limiting, JavaScript popup blocking, overlay ads blocking, and video link extraction. Uses brave-real-puppeteer-core with 50+ stealth features.',
631
631
  inputSchema: {
632
632
  type: 'object',
633
633
  additionalProperties: false,
@@ -635,7 +635,7 @@ export const TOOLS = [
635
635
  startUrls: {
636
636
  type: 'array',
637
637
  items: { type: 'string' },
638
- description: 'Initial URLs to start crawling from'
638
+ description: 'Initial URLs to start crawling from (movie/streaming pages)'
639
639
  },
640
640
  maxDepth: {
641
641
  type: 'number',
@@ -680,9 +680,25 @@ export const TOOLS = [
680
680
  description: 'Follow discovered links',
681
681
  default: true
682
682
  },
683
+ // Movie streaming specific options
684
+ blockPopups: {
685
+ type: 'boolean',
686
+ description: 'Block JavaScript popup ads and window.open calls',
687
+ default: true
688
+ },
689
+ blockOverlayAds: {
690
+ type: 'boolean',
691
+ description: 'Block overlay ads, modal popups, and floating elements',
692
+ default: true
693
+ },
694
+ extractVideoLinks: {
695
+ type: 'boolean',
696
+ description: 'Auto-extract m3u8, mp4, mkv video links from pages',
697
+ default: true
698
+ },
683
699
  downloadMedia: {
684
700
  type: 'boolean',
685
- description: 'Download images/videos/files',
701
+ description: 'Download video/audio files',
686
702
  default: false
687
703
  },
688
704
  savePath: {
@@ -715,11 +731,6 @@ export const TOOLS = [
715
731
  description: 'Crawl mode (browser = Puppeteer, http = fast HTTP)',
716
732
  default: 'browser'
717
733
  },
718
- respectRobotsTxt: {
719
- type: 'boolean',
720
- description: 'Respect robots.txt rules',
721
- default: true
722
- },
723
734
  userAgent: {
724
735
  type: 'string',
725
736
  description: 'Custom User-Agent string'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brave-real-browser-mcp-server",
3
- "version": "2.25.0",
3
+ "version": "2.26.0",
4
4
  "description": "🦁 MCP server for Brave Real Browser - NPM Workspaces Monorepo with anti-detection features, SSE streaming, and LSP compatibility",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -50,7 +50,7 @@
50
50
  "dependencies": {
51
51
  "@modelcontextprotocol/sdk": "latest",
52
52
  "@types/turndown": "latest",
53
- "brave-real-browser": "^2.6.0",
53
+ "brave-real-browser": "^2.7.0",
54
54
  "crawlee": "^3.15.3",
55
55
  "puppeteer-core": "^24.35.0",
56
56
  "turndown": "latest",