Automatically detects and claims rain bonuses on Supabets gaming platform
Size
6.2 KB
Version
1.0.1
Created
Feb 3, 2026
Updated
about 11 hours ago
1// ==UserScript==
2// @name Supabets Rain Auto-Claimer
3// @description Automatically detects and claims rain bonuses on Supabets gaming platform
4// @version 1.0.1
5// @match https://*.gaming.supabets.co.za/*
6// @icon https://gaming.supabets.co.za/images/gaming.supabets.co.za/favicon/favicon.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Supabets Rain Auto-Claimer initialized');
12
13 // Debounce function to prevent excessive calls
14 function debounce(func, wait) {
15 let timeout;
16 return function executedFunction(...args) {
17 const later = () => {
18 clearTimeout(timeout);
19 func(...args);
20 };
21 clearTimeout(timeout);
22 timeout = setTimeout(later, wait);
23 };
24 }
25
26 // Function to check for rain notifications and claim them
27 async function checkForRain() {
28 console.log('Checking for rain notifications...');
29
30 // Look for rain-related elements with multiple possible selectors
31 const rainSelectors = [
32 'button[class*="rain" i]',
33 'button[id*="rain" i]',
34 '[class*="rain" i] button',
35 '[id*="rain" i] button',
36 'button:has-text("rain")',
37 'button:has-text("Rain")',
38 'button:has-text("RAIN")',
39 '[role="button"][class*="rain" i]',
40 '[role="button"][id*="rain" i]',
41 '.modal button[class*="claim" i]',
42 '.popup button[class*="claim" i]',
43 '[class*="notification" i] button[class*="claim" i]',
44 'button[class*="bonus" i][class*="claim" i]'
45 ];
46
47 // Try each selector
48 for (const selector of rainSelectors) {
49 try {
50 const elements = document.querySelectorAll(selector);
51 for (const element of elements) {
52 const text = element.textContent.toLowerCase();
53 const isVisible = element.offsetParent !== null;
54
55 if (isVisible && (text.includes('rain') || text.includes('claim'))) {
56 console.log('Found potential rain claim button:', element);
57 console.log('Button text:', element.textContent);
58 console.log('Button classes:', element.className);
59
60 // Click the button
61 element.click();
62 console.log('Clicked rain claim button!');
63
64 // Store claim timestamp
65 const timestamp = new Date().toISOString();
66 await GM.setValue('lastRainClaim', timestamp);
67 console.log('Rain claimed at:', timestamp);
68
69 return true;
70 }
71 }
72 } catch (error) {
73 // Selector might not be valid, continue to next one
74 continue;
75 }
76 }
77
78 // Also check for any buttons containing "rain" or "claim" in visible modals/popups
79 const modals = document.querySelectorAll('[class*="modal" i]:not([style*="display: none"]), [class*="popup" i]:not([style*="display: none"]), [class*="notification" i]:not([style*="display: none"])');
80
81 for (const modal of modals) {
82 const buttons = modal.querySelectorAll('button, [role="button"]');
83 for (const button of buttons) {
84 const text = button.textContent.toLowerCase();
85 const isVisible = button.offsetParent !== null;
86
87 if (isVisible && (text.includes('rain') || text.includes('claim') || text.includes('collect'))) {
88 console.log('Found rain claim button in modal:', button);
89 console.log('Button text:', button.textContent);
90
91 button.click();
92 console.log('Clicked rain claim button in modal!');
93
94 const timestamp = new Date().toISOString();
95 await GM.setValue('lastRainClaim', timestamp);
96 console.log('Rain claimed at:', timestamp);
97
98 return true;
99 }
100 }
101 }
102
103 return false;
104 }
105
106 // Debounced version of checkForRain
107 const debouncedCheckForRain = debounce(checkForRain, 1000);
108
109 // Set up MutationObserver to watch for DOM changes
110 function setupObserver() {
111 console.log('Setting up MutationObserver for rain detection...');
112
113 const observer = new MutationObserver(debouncedCheckForRain);
114
115 observer.observe(document.body, {
116 childList: true,
117 subtree: true,
118 attributes: true,
119 attributeFilter: ['class', 'style']
120 });
121
122 console.log('MutationObserver active - monitoring for rain notifications');
123 }
124
125 // Initialize the extension
126 async function init() {
127 console.log('Initializing Supabets Rain Auto-Claimer...');
128
129 // Check for last claim time
130 const lastClaim = await GM.getValue('lastRainClaim', null);
131 if (lastClaim) {
132 console.log('Last rain claim was at:', lastClaim);
133 }
134
135 // Initial check
136 await checkForRain();
137
138 // Set up observer for dynamic content
139 if (document.body) {
140 setupObserver();
141 } else {
142 // Wait for body to be available
143 const bodyObserver = new MutationObserver((mutations, obs) => {
144 if (document.body) {
145 setupObserver();
146 obs.disconnect();
147 }
148 });
149 bodyObserver.observe(document.documentElement, { childList: true });
150 }
151
152 // Periodic check every 30 seconds as backup
153 setInterval(checkForRain, 30000);
154
155 console.log('Supabets Rain Auto-Claimer is now active!');
156 }
157
158 // Start the extension when DOM is ready
159 if (document.readyState === 'loading') {
160 document.addEventListener('DOMContentLoaded', init);
161 } else {
162 init();
163 }
164
165})();