BetNare Auto Rain Claimer

Automatically claims rain rewards on BetNare

Size

7.4 KB

Version

1.0.1

Created

Mar 8, 2026

Updated

14 days ago

1// ==UserScript==
2// @name		BetNare Auto Rain Claimer
3// @description		Automatically claims rain rewards on BetNare
4// @version		1.0.1
5// @match		https://*.betnare.com/*
6// @icon		https://pcdn.i-gamingplatform.com/d8a6fb4680ad860c4f6b862f1bb5b8d4/global_config/d0513638-7539-46d7-b339-37373b8f2be2.webp
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.xmlhttpRequest
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('BetNare Auto Rain Claimer - Extension loaded');
15
16    // Configuration
17    const CONFIG = {
18        checkInterval: 1000, // Check every 1 second
19        claimDelay: 500, // Delay before claiming (ms)
20        maxRetries: 3
21    };
22
23    // Debounce function to prevent multiple rapid calls
24    function debounce(func, wait) {
25        let timeout;
26        return function executedFunction(...args) {
27            const later = () => {
28                clearTimeout(timeout);
29                func(...args);
30            };
31            clearTimeout(timeout);
32            timeout = setTimeout(later, wait);
33        };
34    }
35
36    // Function to find rain claim button
37    function findRainClaimButton() {
38        // Look for common rain claim button patterns
39        const selectors = [
40            'button[class*="rain"][class*="claim"]',
41            'button[class*="claim"][class*="rain"]',
42            'div[class*="rain"] button[class*="claim"]',
43            'div[class*="rain-modal"] button',
44            'div[class*="rain-popup"] button',
45            '[data-testid*="rain-claim"]',
46            '[data-testid*="claim-rain"]',
47            'button:has-text("Claim Rain")',
48            'button:has-text("Claim")'
49        ];
50
51        for (const selector of selectors) {
52            try {
53                const elements = document.querySelectorAll(selector);
54                for (const element of elements) {
55                    const text = element.textContent?.toLowerCase() || '';
56                    const classes = element.className?.toLowerCase() || '';
57                    const ariaLabel = element.getAttribute('aria-label')?.toLowerCase() || '';
58                    
59                    if (text.includes('rain') || text.includes('claim') || 
60                        classes.includes('rain') || ariaLabel.includes('rain')) {
61                        console.log('Found potential rain claim button:', element);
62                        return element;
63                    }
64                }
65            } catch (e) {
66                // Skip invalid selectors
67            }
68        }
69
70        // Fallback: search all buttons for rain-related text
71        const allButtons = document.querySelectorAll('button, [role="button"], a[class*="button"]');
72        for (const button of allButtons) {
73            const text = button.textContent?.toLowerCase() || '';
74            const classes = button.className?.toLowerCase() || '';
75            
76            if ((text.includes('rain') && text.includes('claim')) || 
77                (classes.includes('rain') && classes.includes('claim'))) {
78                console.log('Found rain claim button via fallback:', button);
79                return button;
80            }
81        }
82
83        return null;
84    }
85
86    // Function to find rain notification/modal
87    function findRainNotification() {
88        const selectors = [
89            'div[class*="rain"][class*="modal"]',
90            'div[class*="rain"][class*="popup"]',
91            'div[class*="rain"][class*="notification"]',
92            'div[class*="rain"][class*="alert"]',
93            '[data-testid*="rain"]',
94            'div[role="dialog"][class*="rain"]',
95            'div[role="alertdialog"]'
96        ];
97
98        for (const selector of selectors) {
99            try {
100                const elements = document.querySelectorAll(selector);
101                for (const element of elements) {
102                    const text = element.textContent?.toLowerCase() || '';
103                    if (text.includes('rain') && element.offsetParent !== null) {
104                        console.log('Found rain notification:', element);
105                        return element;
106                    }
107                }
108            } catch (e) {
109                // Skip invalid selectors
110            }
111        }
112
113        return null;
114    }
115
116    // Function to claim rain
117    async function claimRain() {
118        try {
119            const claimButton = findRainClaimButton();
120            
121            if (claimButton && claimButton.offsetParent !== null) {
122                console.log('Attempting to claim rain...');
123                
124                // Check if button is disabled
125                if (claimButton.disabled || claimButton.getAttribute('disabled') !== null) {
126                    console.log('Claim button is disabled');
127                    return false;
128                }
129
130                // Click the button
131                claimButton.click();
132                console.log('Rain claim button clicked!');
133
134                // Update statistics
135                const stats = await GM.getValue('rainClaimStats', { total: 0, lastClaim: null });
136                stats.total += 1;
137                stats.lastClaim = new Date().toISOString();
138                await GM.setValue('rainClaimStats', stats);
139
140                console.log(`Total rain claims: ${stats.total}`);
141                return true;
142            }
143        } catch (error) {
144            console.error('Error claiming rain:', error);
145        }
146        
147        return false;
148    }
149
150    // Main monitoring function
151    const monitorForRain = debounce(async function() {
152        const rainNotification = findRainNotification();
153        const claimButton = findRainClaimButton();
154
155        if (rainNotification || claimButton) {
156            console.log('Rain detected! Attempting to claim...');
157            
158            // Wait a bit before claiming to ensure UI is ready
159            setTimeout(async () => {
160                const claimed = await claimRain();
161                if (claimed) {
162                    console.log('Rain successfully claimed!');
163                }
164            }, CONFIG.claimDelay);
165        }
166    }, 500);
167
168    // Set up MutationObserver to watch for rain notifications
169    const observer = new MutationObserver(debounce(function(mutations) {
170        monitorForRain();
171    }, 300));
172
173    // Start observing when body is ready
174    function init() {
175        if (document.body) {
176            console.log('Starting rain monitor...');
177            
178            // Observe DOM changes
179            observer.observe(document.body, {
180                childList: true,
181                subtree: true,
182                attributes: true,
183                attributeFilter: ['class', 'style']
184            });
185
186            // Also check periodically
187            setInterval(monitorForRain, CONFIG.checkInterval);
188
189            // Initial check
190            monitorForRain();
191
192            console.log('Rain monitor active!');
193        } else {
194            setTimeout(init, 100);
195        }
196    }
197
198    // Display statistics on page load
199    async function displayStats() {
200        const stats = await GM.getValue('rainClaimStats', { total: 0, lastClaim: null });
201        console.log('=== Rain Claim Statistics ===');
202        console.log(`Total claims: ${stats.total}`);
203        console.log(`Last claim: ${stats.lastClaim || 'Never'}`);
204        console.log('============================');
205    }
206
207    // Start the extension
208    if (document.readyState === 'loading') {
209        document.addEventListener('DOMContentLoaded', init);
210    } else {
211        init();
212    }
213
214    // Display stats
215    displayStats();
216
217})();