Easybet Voucher Auto Claimer

Automatically claims vouchers on Easybet by filling forms, submitting twice, closing tabs, and refreshing the voucher drop page

Size

19.0 KB

Version

1.0.1

Created

Nov 22, 2025

Updated

20 days ago

1// ==UserScript==
2// @name		Easybet Voucher Auto Claimer
3// @description		Automatically claims vouchers on Easybet by filling forms, submitting twice, closing tabs, and refreshing the voucher drop page
4// @version		1.0.1
5// @match		https://*.easybet.co.za/*
6// @icon		https://s3.eu-central-1.wasabisys.com/online-sa5-c13d78733b/public/17c0075c-eb4e-3e31-75b8-1728a00cc543
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    // =================================================================
12    //  GLOBAL CONFIG & STATE
13    // =================================================================
14    let config = {
15        enabled: false,
16        userId: '5376545',
17        clickedSurveys: [],
18
19        // General Settings
20        scanIntervalMin: 3000,
21        scanIntervalMax: 7000,
22        selectionStrategy: 'first',
23
24        // Humanization Settings
25        reloadScanDelayMin: 2000,
26        reloadScanDelayMax: 5000,
27
28        voucherClickDelayMin: 300,
29        voucherClickDelayMax: 800,
30
31        surveyDelayMin: 1000,
32        surveyDelayMax: 2500,
33
34        typingDelayMin: 80,
35        typingDelayMax: 200,
36
37        validationDelayMin: 200,
38        validationDelayMax: 500,
39
40        submitDelayMin: 500,
41        submitDelayMax: 1200,
42
43        doubleSubmitDelayMin: 500,
44        doubleSubmitDelayMax: 1000,
45
46        doneDelayMin: 1000,
47        doneDelayMax: 2000
48    };
49
50    let easybetInterval = null;
51    let completionListener = null;
52
53    // =================================================================
54    //  HELPER FUNCTIONS
55    // =================================================================
56
57    function randomDelay(min, max) {
58        let nMin = parseInt(min, 10);
59        let nMax = parseInt(max, 10);
60        if (isNaN(nMin)) nMin = 1000;
61        if (isNaN(nMax)) nMax = 3000;
62        if (nMin > nMax) [nMin, nMax] = [nMax, nMin];
63        return Math.floor(Math.random() * (nMax - nMin + 1) + nMin);
64    }
65
66    function logDebug(message) {
67        console.log(`[EB Bot] ${message}`);
68        const logArea = document.getElementById('eb-debug-log');
69        if (logArea) {
70            logArea.value += `[${new Date().toLocaleTimeString()}] ${message}\n`;
71            logArea.scrollTop = logArea.scrollHeight;
72        }
73    }
74
75    function typeText(element, text, callback) {
76        let i = 0;
77        element.focus();
78        function nextChar() {
79            if (i < text.length) {
80                element.value += text[i];
81                element.dispatchEvent(new Event('input', { bubbles: true }));
82                i++;
83                setTimeout(nextChar, randomDelay(config.typingDelayMin, config.typingDelayMax));
84            } else {
85                element.dispatchEvent(new Event('change', { bubbles: true }));
86                element.blur();
87                if (callback) callback();
88            }
89        }
90        setTimeout(nextChar, randomDelay(300, 800));
91    }
92
93    // =================================================================
94    //  CORE AUTOMATION LOGIC
95    // =================================================================
96
97    // --- 1. Easybet Page Logic ---
98    function findAndClickVoucher() {
99        const allUnlockedVouchers = document.querySelectorAll('div.voucher[data-status="unlocked"]');
100        if (allUnlockedVouchers.length === 0) return;
101
102        const eligibleVouchers = Array.from(allUnlockedVouchers).filter(voucher => {
103            const surveyLink = voucher.getAttribute('data-survey-link');
104            if (!surveyLink) return false;
105            try {
106                const surveyId = new URL(surveyLink).searchParams.get('id');
107                return surveyId && !config.clickedSurveys.includes(surveyId);
108            } catch (e) { return false; }
109        });
110
111        if (eligibleVouchers.length === 0) return;
112
113        let voucherToClick;
114        if (config.selectionStrategy === 'random') {
115            logDebug(`Found ${eligibleVouchers.length} eligible vouchers. Picking one at random.`);
116            voucherToClick = eligibleVouchers[Math.floor(Math.random() * eligibleVouchers.length)];
117        } else {
118            logDebug(`Found ${eligibleVouchers.length} eligible vouchers. Picking the first one.`);
119            voucherToClick = eligibleVouchers[0];
120        }
121
122        const voucherId = voucherToClick.id;
123        const surveyId = new URL(voucherToClick.getAttribute('data-survey-link')).searchParams.get('id');
124
125        if (easybetInterval) {
126            clearInterval(easybetInterval);
127            easybetInterval = null;
128        }
129
130        logDebug(`Selected voucher #${voucherId} (Survey: ${surveyId}).`);
131        logDebug("--- SCANNER STOPPED --- Waiting for survey completion signal.");
132
133        config.clickedSurveys.push(surveyId);
134        GM.setValue('eb_clicked_surveys', config.clickedSurveys);
135
136        const clickDelay = randomDelay(config.voucherClickDelayMin, config.voucherClickDelayMax);
137        setTimeout(() => {
138            logDebug(`Clicking voucher #${voucherId}.`);
139            voucherToClick.click();
140        }, clickDelay);
141    }
142
143    // --- 2. SurveyMonkey Page Logic ---
144    function runSurveyBot(userId) {
145        logDebug("Running on SurveyMonkey page.");
146        window.addEventListener('load', () => {
147            const surveyWaitTime = randomDelay(config.surveyDelayMin, config.surveyDelayMax);
148            logDebug(`Survey loaded. Waiting ${surveyWaitTime}ms before filling...`);
149            setTimeout(() => {
150                handleSurvey(userId);
151            }, surveyWaitTime);
152        });
153    }
154
155    function handleSurvey(userId) {
156        const submitButton = document.querySelector('#view-pageNavigation button');
157
158        // --- THANK YOU PAGE LOGIC ---
159        if (document.body.innerText.includes("We hope you get the voucher!")) {
160            logDebug('On "Thank You" page.');
161
162            if (submitButton) {
163                const doneWaitTime = randomDelay(config.doneDelayMin, config.doneDelayMax);
164                logDebug(`Found "Done" button. Finishing in ${doneWaitTime}ms.`);
165
166                setTimeout(() => {
167                    submitButton.click(); // Click Done
168
169                    logDebug("Signal sent: Job Complete. Closing tab...");
170                    // 1. Send Signal to Easybet Tab
171                    GM.setValue('eb_completion_signal', Date.now());
172
173                    // 2. Close this tab
174                    setTimeout(() => {
175                        window.close();
176                    }, 500);
177
178                }, doneWaitTime);
179            } else {
180                // Even if button isn't found, we should probably close
181                logDebug('Done button not found, closing anyway in 2s.');
182                GM.setValue('eb_completion_signal', Date.now());
183                setTimeout(() => { window.close(); }, 2000);
184            }
185        }
186        // --- FORM FILLING LOGIC ---
187        else {
188            logDebug('On survey form page. Looking for fields...');
189            const inputField = document.querySelector('input[type="text"][class*="smqr-inputField-"]');
190
191            if (inputField && submitButton) {
192                logDebug(`Found fields. Submitting ID: ${userId}`);
193
194                typeText(inputField, userId, () => {
195                    logDebug('Typing complete.');
196
197                    const validationWaitTime = randomDelay(config.validationDelayMin, config.validationDelayMax);
198                    setTimeout(() => {
199                        const submitWaitTime = randomDelay(config.submitDelayMin, config.submitDelayMax);
200                        logDebug(`Validation done. Submitting in ${submitWaitTime}ms.`);
201
202                        setTimeout(() => {
203                            logDebug('Submit 1/2.');
204                            submitButton.click();
205
206                            // Double Submit Logic
207                            const doubleWait = randomDelay(config.doubleSubmitDelayMin, config.doubleSubmitDelayMax);
208                            setTimeout(() => {
209                                logDebug('Submit 2/2 (Confirmation Click).');
210                                submitButton.click();
211                            }, doubleWait);
212
213                        }, submitWaitTime);
214
215                    }, validationWaitTime);
216                });
217            } else {
218                if (!inputField) logDebug('Error: Input field not found.');
219                if (!submitButton) logDebug('Error: Submit button not found.');
220            }
221        }
222    }
223
224    // =================================================================
225    //  UI & SETTINGS FUNCTIONS
226    // =================================================================
227
228    function injectUIAndListeners() {
229        TM_addStyle(`
230            #eb-float-button { position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; background-color: #19c2e8; color: white; border-radius: 50%; border: none; font-size: 24px; line-height: 60px; text-align: center; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.3); z-index: 9998; font-family: sans-serif; }
231            #eb-modal-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); z-index: 9999; display: flex; align-items: center; justify-content: center; overflow-y: auto; }
232            #eb-modal-content { background-color: #333; color: #fff; padding: 20px; border-radius: 10px; width: 90%; max-width: 600px; font-family: sans-serif; margin: 20px 0; }
233            #eb-modal-content h2 { margin-top: 0; color: #fed600; }
234            .eb-setting-row { margin-bottom: 15px; display: grid; grid-template-columns: 200px 1fr; align-items: center; gap: 15px; }
235            .eb-setting-row input[type="text"], .eb-setting-row input[type="number"], .eb-setting-row select { padding: 8px; border-radius: 5px; border: 1px solid #777; background: #555; color: #fff; width: 100%; box-sizing: border-box; }
236            .eb-setting-row .eb-time-inputs { display: flex; gap: 10px; }
237            .eb-setting-row .eb-time-inputs input { width: 100px; }
238            #eb-debug-log { width: 100%; height: 150px; background: #222; color: #0f0; border: 1px solid #777; border-radius: 5px; font-family: monospace; font-size: 12px; resize: vertical; box-sizing: border-box; }
239            .eb-button { background-color: #fed600; color: #000; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; }
240            .eb-button.eb-button-secondary { background-color: #555; color: #fff; }
241            .eb-switch { position: relative; display: inline-block; width: 60px; height: 34px; justify-self: start; }
242            .eb-switch input { opacity: 0; width: 0; height: 0; }
243            .eb-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; }
244            .eb-slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; }
245            input:checked + .eb-slider { background-color: #19c2e8; }
246            input:checked + .eb-slider:before { transform: translateX(26px); }
247            .eb-hidden { display: none; }
248            small { color: #aaa; grid-column: 2; margin-top: -10px; }
249        `);
250
251        const buttonHTML = `<button id="eb-float-button" title="Easybet Bot Settings">🤖</button>`;
252        const modalHTML = `
253            <div id="eb-modal-backdrop" class="eb-hidden">
254                <div id="eb-modal-content">
255                    <span id="eb-modal-close" title="Close" style="float:right;cursor:pointer;font-size:24px;">&times;</span>
256                    <h2>🤖 Easybet Bot Settings</h2>
257                    <div class="eb-setting-row">
258                        <label>Enable Bot</label>
259                        <label class="eb-switch"><input type="checkbox" id="eb-setting-enabled"><span class="eb-slider"></span></label>
260                    </div>
261                    <div class="eb-setting-row"><label>User ID</label><input type="text" id="eb-setting-userid"></div>
262                    <div class="eb-setting-row"><label>Strategy</label><select id="eb-setting-strategy"><option value="first">First</option><option value="random">Random</option></select></div>
263                    <h3>Delays (ms)</h3>
264                    <div class="eb-setting-row"><label>Scan Interval</label><div class="eb-time-inputs"><input type="number" id="eb-setting-scan-min" placeholder="Min"><input type="number" id="eb-setting-scan-max" placeholder="Max"></div></div>
265                    <div class="eb-setting-row"><label>Double Click</label><div class="eb-time-inputs"><input type="number" id="eb-setting-double-min" placeholder="Min"><input type="number" id="eb-setting-double-max" placeholder="Max"></div></div>
266                    <textarea id="eb-debug-log" readonly></textarea>
267                    <div style="margin-top: 20px; display: flex; gap: 10px;">
268                        <button id="eb-save-button" class="eb-button">Save</button>
269                        <button id="eb-clear-button" class="eb-button eb-button-secondary">Clear Clicked</button>
270                        <span id="eb-save-status" style="color: #0f0;"></span>
271                    </div>
272                </div>
273            </div>
274        `;
275        document.body.insertAdjacentHTML('beforeend', buttonHTML);
276        document.body.insertAdjacentHTML('beforeend', modalHTML);
277
278        document.getElementById('eb-float-button').addEventListener('click', openModal);
279        document.getElementById('eb-modal-close').addEventListener('click', closeModal);
280        document.getElementById('eb-save-button').addEventListener('click', saveSettings);
281        document.getElementById('eb-clear-button').addEventListener('click', clearClickedList);
282        document.getElementById('eb-modal-backdrop').addEventListener('click', (e) => {
283            if (e.target === e.currentTarget) closeModal();
284        });
285    }
286
287    function openModal() {
288        document.getElementById('eb-setting-enabled').checked = config.enabled;
289        document.getElementById('eb-setting-userid').value = config.userId;
290        document.getElementById('eb-setting-strategy').value = config.selectionStrategy;
291        document.getElementById('eb-setting-scan-min').value = config.scanIntervalMin;
292        document.getElementById('eb-setting-scan-max').value = config.scanIntervalMax;
293        document.getElementById('eb-setting-double-min').value = config.doubleSubmitDelayMin;
294        document.getElementById('eb-setting-double-max').value = config.doubleSubmitDelayMax;
295        document.getElementById('eb-save-status').innerText = '';
296        document.getElementById('eb-modal-backdrop').classList.remove('eb-hidden');
297    }
298
299    function closeModal() {
300        document.getElementById('eb-modal-backdrop').classList.add('eb-hidden');
301    }
302
303    function getIntFromUI(id, defaultValue) {
304        let val = parseInt(document.getElementById(id).value, 10);
305        return isNaN(val) ? defaultValue : val;
306    }
307
308    async function loadSettings() {
309        config.enabled = await GM.getValue('eb_enabled', false);
310        config.userId = await GM.getValue('eb_userId', '5376545');
311        config.clickedSurveys = await GM.getValue('eb_clicked_surveys', []);
312        config.scanIntervalMin = await GM.getValue('eb_scan_min', 3000);
313        config.scanIntervalMax = await GM.getValue('eb_scan_max', 7000);
314        config.selectionStrategy = await GM.getValue('eb_strategy', 'first');
315        config.doubleSubmitDelayMin = await GM.getValue('eb_double_min', 500);
316        config.doubleSubmitDelayMax = await GM.getValue('eb_double_max', 1000);
317    }
318
319    async function saveSettings() {
320        config.enabled = document.getElementById('eb-setting-enabled').checked;
321        config.userId = document.getElementById('eb-setting-userid').value.trim();
322        config.selectionStrategy = document.getElementById('eb-setting-strategy').value;
323        config.scanIntervalMin = getIntFromUI('eb-setting-scan-min', 3000);
324        config.scanIntervalMax = getIntFromUI('eb-setting-scan-max', 7000);
325        config.doubleSubmitDelayMin = getIntFromUI('eb-setting-double-min', 500);
326        config.doubleSubmitDelayMax = getIntFromUI('eb-setting-double-max', 1000);
327
328        await GM.setValue('eb_enabled', config.enabled);
329        await GM.setValue('eb_userId', config.userId);
330        await GM.setValue('eb_strategy', config.selectionStrategy);
331        await GM.setValue('eb_scan_min', config.scanIntervalMin);
332        await GM.setValue('eb_scan_max', config.scanIntervalMax);
333        await GM.setValue('eb_double_min', config.doubleSubmitDelayMin);
334        await GM.setValue('eb_double_max', config.doubleSubmitDelayMax);
335
336        const saveStatus = document.getElementById('eb-save-status');
337        saveStatus.innerText = 'Saved!';
338        setTimeout(() => { saveStatus.innerText = ''; }, 2000);
339        startAutomation();
340    }
341
342    async function clearClickedList() {
343        if (confirm('Clear clicked vouchers list?')) {
344            config.clickedSurveys = [];
345            await GM.setValue('eb_clicked_surveys', []);
346            document.getElementById('eb-save-status').innerText = 'Cleared!';
347        }
348    }
349
350    // =================================================================
351    //  INITIALIZATION
352    // =================================================================
353
354    async function startAutomation() {
355        // Clear existing intervals
356        if (easybetInterval) clearInterval(easybetInterval);
357        if (completionListener) clearInterval(completionListener);
358
359        if (!config.enabled) {
360            logDebug("Bot is disabled.");
361            return;
362        }
363
364        const hostname = window.location.hostname;
365
366        // --- EASYBET PAGE ---
367        if (hostname.includes('easybet.co.za')) {
368            const firstScanDelay = randomDelay(config.reloadScanDelayMin, config.reloadScanDelayMax);
369            logDebug(`On Easybet. Starting scan in ${firstScanDelay}ms...`);
370
371            // 1. Start Scanners
372            setTimeout(() => {
373                findAndClickVoucher();
374                const scanTime = randomDelay(config.scanIntervalMin, config.scanIntervalMax);
375                easybetInterval = setInterval(findAndClickVoucher, scanTime);
376            }, firstScanDelay);
377
378            // 2. Start Completion Listener (Checks for signal from Survey tab)
379            let loadTime = Date.now();
380            completionListener = setInterval(async () => {
381                const lastSignal = await GM.getValue('eb_completion_signal', 0);
382                if (lastSignal > loadTime) {
383                    logDebug("Received completion signal! Redirecting to Voucher Drop...");
384                    loadTime = Date.now();
385                    window.location.href = 'https://easybet.co.za/page/voucher-drop';
386                }
387            }, 1000);
388        }
389        // --- SURVEYMONKEY PAGE ---
390        else if (hostname.includes('surveymonkey.com')) {
391            runSurveyBot(config.userId);
392        }
393    }
394
395    // =================================================================
396    //  MAIN EXECUTION
397    // =================================================================
398
399    async function init() {
400        await loadSettings();
401        
402        if (window.top === window.self) {
403            TM_runBody(() => {
404                injectUIAndListeners();
405            });
406        }
407
408        startAutomation();
409    }
410
411    init();
412
413})();
Easybet Voucher Auto Claimer | Robomonkey