Binance Red Packet Auto Claimer

Automatically claims red packets on Binance and monitors Binance Square for new opportunities

Size

21.7 KB

Version

1.1.2

Created

Feb 28, 2026

Updated

about 2 months ago

1// ==UserScript==
2// @name		Binance Red Packet Auto Claimer
3// @description		Automatically claims red packets on Binance and monitors Binance Square for new opportunities
4// @version		1.1.2
5// @match		https://*.binance.com/*
6// @match		https://www.binance.com/*
7// @icon		https://web.telegram.org/k/assets/img/favicon.ico?v=jw3mK7G9Ry
8// ==/UserScript==
9(function() {
10    'use strict';
11
12    console.log('Binance Red Packet Auto Claimer initialized');
13
14    // Configuration
15    const CONFIG = {
16        CHECK_INTERVAL: 5000, // Check every 5 seconds
17        SQUARE_CHECK_INTERVAL: 30000, // Check Binance Square every 30 seconds
18        AUTO_CLAIM_ENABLED: true,
19        MONITOR_SQUARE: true
20    };
21
22    // State management
23    let claimedPackets = [];
24    let isProcessing = false;
25
26    // Initialize state from storage
27    async function initState() {
28        try {
29            const saved = await GM.getValue('claimedPackets', '[]');
30            claimedPackets = JSON.parse(saved);
31            console.log('Loaded claimed packets:', claimedPackets.length);
32        } catch (error) {
33            console.error('Error loading state:', error);
34            claimedPackets = [];
35        }
36    }
37
38    // Save state to storage
39    async function saveState() {
40        try {
41            await GM.setValue('claimedPackets', JSON.stringify(claimedPackets));
42        } catch (error) {
43            console.error('Error saving state:', error);
44        }
45    }
46
47    // Debounce function to prevent excessive calls
48    function debounce(func, wait) {
49        let timeout;
50        return function executedFunction(...args) {
51            const later = () => {
52                clearTimeout(timeout);
53                func(...args);
54            };
55            clearTimeout(timeout);
56            timeout = setTimeout(later, wait);
57        };
58    }
59
60    // Check if packet was already claimed
61    function isPacketClaimed(packetId) {
62        return claimedPackets.includes(packetId);
63    }
64
65    // Mark packet as claimed
66    async function markPacketClaimed(packetId) {
67        if (!claimedPackets.includes(packetId)) {
68            claimedPackets.push(packetId);
69            await saveState();
70            console.log('Marked packet as claimed:', packetId);
71        }
72    }
73
74    // Find red packet elements on the page
75    function findRedPacketElements() {
76        const selectors = [
77            // Red packet claim buttons
78            'button[class*="red-packet"]',
79            'button[class*="redpacket"]',
80            'button[class*="claim"]',
81            'div[class*="red-packet"]',
82            'div[class*="redpacket"]',
83            // Binance Pay red packet
84            'button[data-bn-type="button"][class*="red"]',
85            'a[href*="red-packet"]',
86            'a[href*="redpacket"]',
87            // Modal and popup elements
88            'div[class*="modal"][class*="red"]',
89            'div[class*="popup"][class*="red"]'
90        ];
91
92        const elements = [];
93        selectors.forEach(selector => {
94            try {
95                const found = document.querySelectorAll(selector);
96                found.forEach(el => {
97                    const text = el.textContent.toLowerCase();
98                    if (text.includes('claim') || text.includes('red packet') || text.includes('receive')) {
99                        elements.push(el);
100                    }
101                });
102            } catch (error) {
103                console.error('Error with selector:', selector, error);
104            }
105        });
106
107        return elements;
108    }
109
110    // Extract red packet code from URL or page
111    function extractRedPacketCode() {
112        // Check URL for red packet code
113        const urlParams = new URLSearchParams(window.location.search);
114        const codeFromUrl = urlParams.get('code') || urlParams.get('ref');
115        
116        if (codeFromUrl) {
117            return codeFromUrl;
118        }
119
120        // Check page content for red packet codes
121        const bodyText = document.body.textContent;
122        const codePattern = /[A-Z0-9]{8,16}/g;
123        const matches = bodyText.match(codePattern);
124        
125        return matches ? matches[0] : null;
126    }
127
128    // Attempt to claim a red packet
129    async function claimRedPacket(element) {
130        if (isProcessing) {
131            console.log('Already processing a claim, skipping...');
132            return false;
133        }
134
135        isProcessing = true;
136        console.log('Attempting to claim red packet...');
137
138        try {
139            // Extract packet ID if available
140            const packetId = element.getAttribute('data-packet-id') || 
141                           element.getAttribute('id') || 
142                           extractRedPacketCode() ||
143                           Date.now().toString();
144
145            // Check if already claimed
146            if (isPacketClaimed(packetId)) {
147                console.log('Packet already claimed:', packetId);
148                return false;
149            }
150
151            // Click the claim button
152            if (element.tagName === 'BUTTON' || element.tagName === 'A') {
153                element.click();
154                console.log('Clicked claim button');
155            } else {
156                // Try to find a button inside the element
157                const button = element.querySelector('button') || element.querySelector('a');
158                if (button) {
159                    button.click();
160                    console.log('Clicked nested button');
161                }
162            }
163
164            // Wait for claim to process
165            await new Promise(resolve => setTimeout(resolve, 2000));
166
167            // Look for success indicators
168            const successIndicators = [
169                'success',
170                'claimed',
171                'received',
172                'congratulations'
173            ];
174
175            const pageText = document.body.textContent.toLowerCase();
176            const isSuccess = successIndicators.some(indicator => pageText.includes(indicator));
177
178            if (isSuccess) {
179                await markPacketClaimed(packetId);
180                console.log('Successfully claimed red packet:', packetId);
181                showNotification('Red packet claimed successfully!', 'success');
182                
183                // Auto-reply to author and Telegram channel
184                await autoReplyToAuthorAndChannel();
185                
186                return true;
187            } else {
188                console.log('Claim status unclear, marking as attempted');
189                await markPacketClaimed(packetId);
190                return false;
191            }
192
193        } catch (error) {
194            console.error('Error claiming red packet:', error);
195            return false;
196        } finally {
197            isProcessing = false;
198        }
199    }
200
201    // Auto-reply to author and Telegram channel
202    async function autoReplyToAuthorAndChannel() {
203        console.log('Attempting to auto-reply to author and Telegram channel...');
204        
205        try {
206            // Wait for any modals or reply sections to appear
207            await new Promise(resolve => setTimeout(resolve, 2000));
208            
209            // Look for reply/answer text on the page
210            const replyText = extractReplyOrAnswerText();
211            
212            if (replyText) {
213                console.log('Found reply text:', replyText);
214                
215                // Find reply input fields
216                const replyInputSelectors = [
217                    'textarea[placeholder*="reply"]',
218                    'textarea[placeholder*="comment"]',
219                    'textarea[placeholder*="answer"]',
220                    'input[placeholder*="reply"]',
221                    'input[placeholder*="comment"]',
222                    'input[placeholder*="answer"]',
223                    'textarea[class*="reply"]',
224                    'textarea[class*="comment"]',
225                    'input[class*="reply"]',
226                    'input[class*="comment"]',
227                    'div[contenteditable="true"]'
228                ];
229                
230                let replyInput = null;
231                for (const selector of replyInputSelectors) {
232                    replyInput = document.querySelector(selector);
233                    if (replyInput) {
234                        console.log('Found reply input with selector:', selector);
235                        break;
236                    }
237                }
238                
239                if (replyInput) {
240                    // Fill in the reply text
241                    if (replyInput.tagName === 'DIV') {
242                        replyInput.textContent = replyText;
243                        replyInput.dispatchEvent(new Event('input', { bubbles: true }));
244                    } else {
245                        replyInput.value = replyText;
246                        replyInput.dispatchEvent(new Event('input', { bubbles: true }));
247                        replyInput.dispatchEvent(new Event('change', { bubbles: true }));
248                    }
249                    
250                    console.log('Filled reply input with text');
251                    
252                    // Wait a moment for the input to register
253                    await new Promise(resolve => setTimeout(resolve, 1000));
254                    
255                    // Find and click submit button
256                    const submitButtonSelectors = [
257                        'button[type="submit"]',
258                        'button[class*="submit"]',
259                        'button[class*="send"]',
260                        'button[class*="reply"]',
261                        'button:has(svg)',
262                        'button[aria-label*="send"]',
263                        'button[aria-label*="submit"]',
264                        'button[aria-label*="reply"]'
265                    ];
266                    
267                    let submitButton = null;
268                    for (const selector of submitButtonSelectors) {
269                        const buttons = document.querySelectorAll(selector);
270                        for (const btn of buttons) {
271                            const btnText = btn.textContent.toLowerCase();
272                            if (btnText.includes('send') || btnText.includes('submit') || btnText.includes('reply') || btn.querySelector('svg')) {
273                                submitButton = btn;
274                                break;
275                            }
276                        }
277                        if (submitButton) break;
278                    }
279                    
280                    if (submitButton) {
281                        submitButton.click();
282                        console.log('Clicked submit button for reply');
283                        showNotification('Auto-replied to author and Telegram channel!', 'success');
284                        
285                        // Wait for submission to complete
286                        await new Promise(resolve => setTimeout(resolve, 2000));
287                    } else {
288                        console.log('Could not find submit button for reply');
289                        showNotification('Reply text filled, please submit manually', 'info');
290                    }
291                } else {
292                    console.log('Could not find reply input field');
293                }
294            } else {
295                console.log('No reply text found on page');
296            }
297            
298        } catch (error) {
299            console.error('Error auto-replying:', error);
300        }
301    }
302
303    // Extract reply or answer text from the page
304    function extractReplyOrAnswerText() {
305        try {
306            // Look for common patterns where answer/reply text is displayed
307            const answerPatterns = [
308                // Text after "Answer:", "Reply:", etc.
309                /(?:answer|reply|response)[:\s]+([^\n]+)/gi,
310                // Text in elements with answer/reply classes
311                '[class*="answer"]',
312                '[class*="reply"]',
313                '[data-answer]',
314                '[data-reply]',
315                // Text near "To claim" or "Answer to claim"
316                /(?:to claim|answer to claim)[:\s]+([^\n]+)/gi
317            ];
318            
319            // Try regex patterns first
320            const pageText = document.body.textContent;
321            for (const pattern of answerPatterns) {
322                if (pattern instanceof RegExp) {
323                    const match = pageText.match(pattern);
324                    if (match && match[1]) {
325                        return match[1].trim();
326                    }
327                }
328            }
329            
330            // Try element selectors
331            for (const pattern of answerPatterns) {
332                if (typeof pattern === 'string') {
333                    const element = document.querySelector(pattern);
334                    if (element && element.textContent.trim()) {
335                        return element.textContent.trim();
336                    }
337                }
338            }
339            
340            // Look for text in modal or popup that might contain the answer
341            const modalSelectors = [
342                'div[class*="modal"]',
343                'div[class*="popup"]',
344                'div[class*="dialog"]',
345                'div[role="dialog"]'
346            ];
347            
348            for (const selector of modalSelectors) {
349                const modal = document.querySelector(selector);
350                if (modal) {
351                    const modalText = modal.textContent;
352                    // Look for answer patterns in modal
353                    const answerMatch = modalText.match(/(?:answer|reply)[:\s]+([^\n]+)/i);
354                    if (answerMatch && answerMatch[1]) {
355                        return answerMatch[1].trim();
356                    }
357                }
358            }
359            
360            return null;
361        } catch (error) {
362            console.error('Error extracting reply text:', error);
363            return null;
364        }
365    }
366
367    // Monitor Binance Square for red packets
368    async function monitorBinanceSquare() {
369        if (!CONFIG.MONITOR_SQUARE) return;
370
371        console.log('Monitoring Binance Square for red packets...');
372
373        try {
374            // Check if we're on Binance Square
375            if (window.location.href.includes('/square')) {
376                // Look for red packet posts
377                const posts = document.querySelectorAll('a[href*="/square/post"]');
378                
379                for (const post of posts) {
380                    const text = post.textContent.toLowerCase();
381                    if (text.includes('red packet') || text.includes('redpacket') || text.includes('giveaway') || text.includes('gift')) {
382                        console.log('Found potential red packet post:', post.href);
383                        
384                        // Check if we've already processed this post
385                        const postId = post.href.split('/').pop();
386                        if (!isPacketClaimed('square_' + postId)) {
387                            // Mark as seen
388                            await markPacketClaimed('square_' + postId);
389                            
390                            // Auto-open the post to claim
391                            console.log('Auto-opening red packet post:', post.href);
392                            showNotification('Found red packet in Binance Square! Opening...', 'info');
393                            
394                            // Open in current tab to auto-claim
395                            window.location.href = post.href;
396                            return; // Exit to allow page to load
397                        }
398                    }
399                }
400                
401                // Also check for red packet codes in visible posts
402                await extractAndClaimCodesFromSquare();
403            }
404        } catch (error) {
405            console.error('Error monitoring Binance Square:', error);
406        }
407    }
408
409    // Extract and claim red packet codes from Binance Square posts
410    async function extractAndClaimCodesFromSquare() {
411        try {
412            // Look for red packet codes in post content
413            const postContents = document.querySelectorAll('[class*="post-content"], [class*="article"], [class*="content"]');
414            
415            for (const content of postContents) {
416                const text = content.textContent;
417                
418                // Look for red packet code patterns
419                const codePatterns = [
420                    /code[:\s]+([A-Z0-9]{8,16})/gi,
421                    /red packet[:\s]+([A-Z0-9]{8,16})/gi,
422                    /claim[:\s]+([A-Z0-9]{8,16})/gi,
423                    /\b([A-Z0-9]{8,16})\b/g
424                ];
425                
426                for (const pattern of codePatterns) {
427                    const matches = text.matchAll(pattern);
428                    for (const match of matches) {
429                        const code = match[1] || match[0];
430                        
431                        if (code && !isPacketClaimed('code_' + code)) {
432                            console.log('Found red packet code in Square:', code);
433                            await markPacketClaimed('code_' + code);
434                            
435                            // Navigate to red packet claim page
436                            const claimUrl = `https://www.binance.com/en/my/wallet/account/payment/cryptobox?code=${code}`;
437                            showNotification('Found red packet code! Claiming...', 'info');
438                            window.location.href = claimUrl;
439                            return;
440                        }
441                    }
442                }
443            }
444        } catch (error) {
445            console.error('Error extracting codes from Square:', error);
446        }
447    }
448
449    // Show notification to user
450    function showNotification(message, type = 'info') {
451        const notification = document.createElement('div');
452        notification.style.cssText = `
453            position: fixed;
454            top: 20px;
455            right: 20px;
456            background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
457            color: white;
458            padding: 16px 24px;
459            border-radius: 8px;
460            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
461            z-index: 999999;
462            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
463            font-size: 14px;
464            font-weight: 500;
465            max-width: 300px;
466            animation: slideIn 0.3s ease-out;
467        `;
468        notification.textContent = message;
469        document.body.appendChild(notification);
470
471        setTimeout(() => {
472            notification.style.animation = 'slideOut 0.3s ease-out';
473            setTimeout(() => notification.remove(), 300);
474        }, 5000);
475    }
476
477    // Add CSS animations
478    const style = document.createElement('style');
479    style.textContent = `
480        @keyframes slideIn {
481            from {
482                transform: translateX(400px);
483                opacity: 0;
484            }
485            to {
486                transform: translateX(0);
487                opacity: 1;
488            }
489        }
490        @keyframes slideOut {
491            from {
492                transform: translateX(0);
493                opacity: 1;
494            }
495            to {
496                transform: translateX(400px);
497                opacity: 0;
498            }
499        }
500    `;
501    document.head.appendChild(style);
502
503    // Main monitoring loop
504    async function monitorForRedPackets() {
505        if (!CONFIG.AUTO_CLAIM_ENABLED) return;
506
507        try {
508            // Find red packet elements
509            const redPacketElements = findRedPacketElements();
510            
511            if (redPacketElements.length > 0) {
512                console.log('Found', redPacketElements.length, 'potential red packet elements');
513                
514                // Try to claim the first unclaimed packet
515                for (const element of redPacketElements) {
516                    const claimed = await claimRedPacket(element);
517                    if (claimed) {
518                        break; // Only claim one at a time
519                    }
520                }
521            }
522        } catch (error) {
523            console.error('Error in monitoring loop:', error);
524        }
525    }
526
527    // Handle red packet URLs directly
528    function handleRedPacketUrl() {
529        const url = window.location.href;
530        
531        // Check if URL contains red packet parameters
532        if (url.includes('red-packet') || url.includes('redpacket') || url.includes('/pay/')) {
533            console.log('Red packet URL detected, attempting auto-claim...');
534            
535            // Wait for page to load then try to claim
536            setTimeout(() => {
537                const claimButtons = findRedPacketElements();
538                if (claimButtons.length > 0) {
539                    claimRedPacket(claimButtons[0]);
540                }
541            }, 3000);
542        }
543    }
544
545    // Observe DOM changes for dynamically loaded red packets
546    const observer = new MutationObserver(debounce(() => {
547        if (CONFIG.AUTO_CLAIM_ENABLED) {
548            monitorForRedPackets();
549        }
550    }, 1000));
551
552    // Initialize the extension
553    async function init() {
554        console.log('Starting Binance Red Packet Auto Claimer...');
555        
556        // Initialize state
557        await initState();
558        
559        // Handle direct red packet URLs
560        handleRedPacketUrl();
561        
562        // Start monitoring
563        setInterval(monitorForRedPackets, CONFIG.CHECK_INTERVAL);
564        setInterval(monitorBinanceSquare, CONFIG.SQUARE_CHECK_INTERVAL);
565        
566        // Observe DOM changes
567        observer.observe(document.body, {
568            childList: true,
569            subtree: true
570        });
571        
572        console.log('Binance Red Packet Auto Claimer is now active!');
573        showNotification('Red Packet Auto Claimer is active!', 'success');
574    }
575
576    // Wait for page to be ready
577    if (document.readyState === 'loading') {
578        document.addEventListener('DOMContentLoaded', init);
579    } else {
580        init();
581    }
582
583})();
Binance Red Packet Auto Claimer | Robomonkey