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

21 days 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})();