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