Automatically extracts red packet codes from Telegram and claims them on Binance
Size
21.1 KB
Version
1.0.1
Created
Nov 13, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Binance Red Packet Auto Claimer
3// @description Automatically extracts red packet codes from Telegram and claims them on Binance
4// @version 1.0.1
5// @match https://*.web.telegram.org/*
6// @match https://www.binance.com/en/my/wallet/account/payment/cryptobox
7// @icon https://web.telegram.org/a/favicon.ico
8// @grant GM.getValue
9// @grant GM.setValue
10// @grant GM.deleteValue
11// ==/UserScript==
12(function() {
13 'use strict';
14
15 console.log('Binance Red Packet Auto Claimer - Extension loaded');
16
17 // Utility function to wait for element
18 function waitForElement(selector, timeout = 10000) {
19 return new Promise((resolve, reject) => {
20 const element = document.querySelector(selector);
21 if (element) {
22 return resolve(element);
23 }
24
25 const observer = new MutationObserver((mutations, obs) => {
26 const element = document.querySelector(selector);
27 if (element) {
28 obs.disconnect();
29 resolve(element);
30 }
31 });
32
33 observer.observe(document.body, {
34 childList: true,
35 subtree: true
36 });
37
38 setTimeout(() => {
39 observer.disconnect();
40 reject(new Error(`Element ${selector} not found within ${timeout}ms`));
41 }, timeout);
42 });
43 }
44
45 // Utility function to delay
46 function delay(ms) {
47 return new Promise(resolve => setTimeout(resolve, ms));
48 }
49
50 // ==================== TELEGRAM FUNCTIONALITY ====================
51 async function extractCodesFromTelegram() {
52 console.log('Starting code extraction from Telegram...');
53
54 // Find all code elements in messages
55 const codeElements = document.querySelectorAll('code.text-entity-code[data-entity-type="MessageEntityCode"]');
56 console.log(`Found ${codeElements.length} code elements`);
57
58 const codes = [];
59 codeElements.forEach(codeEl => {
60 const code = codeEl.textContent.trim();
61 if (code && code.length > 0) {
62 codes.push(code);
63 }
64 });
65
66 console.log(`Extracted ${codes.length} red packet codes:`, codes);
67
68 // Store codes in GM storage
69 if (codes.length > 0) {
70 await GM.setValue('redPacketCodes', JSON.stringify(codes));
71 console.log('Codes saved to storage');
72 }
73
74 return codes;
75 }
76
77 async function setupTelegramExtractor() {
78 console.log('Setting up Telegram code extractor...');
79
80 // Create control panel
81 const controlPanel = document.createElement('div');
82 controlPanel.id = 'telegram-extractor-panel';
83 controlPanel.style.cssText = `
84 position: fixed;
85 top: 80px;
86 right: 20px;
87 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
88 color: white;
89 padding: 20px;
90 border-radius: 12px;
91 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
92 z-index: 10000;
93 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
94 min-width: 280px;
95 backdrop-filter: blur(10px);
96 `;
97
98 controlPanel.innerHTML = `
99 <div style="font-size: 16px; font-weight: bold; margin-bottom: 15px; display: flex; align-items: center; gap: 8px;">
100 <span style="font-size: 20px;">🎁</span>
101 Red Packet Extractor
102 </div>
103 <div style="font-size: 13px; margin-bottom: 15px; opacity: 0.9; line-height: 1.4;">
104 Extract codes from this channel and claim them on Binance
105 </div>
106 <div id="codes-count" style="font-size: 14px; margin-bottom: 15px; padding: 10px; background: rgba(255,255,255,0.2); border-radius: 8px; text-align: center;">
107 <span style="font-size: 24px; font-weight: bold;" id="count-number">0</span>
108 <div style="font-size: 12px; margin-top: 4px; opacity: 0.9;">codes found</div>
109 </div>
110 <button id="extract-btn" style="
111 width: 100%;
112 padding: 12px;
113 background: white;
114 color: #667eea;
115 border: none;
116 border-radius: 8px;
117 font-weight: bold;
118 cursor: pointer;
119 font-size: 14px;
120 transition: all 0.3s;
121 margin-bottom: 10px;
122 ">Extract Codes</button>
123 <button id="clear-codes-btn" style="
124 width: 100%;
125 padding: 10px;
126 background: rgba(255,255,255,0.2);
127 color: white;
128 border: 1px solid rgba(255,255,255,0.3);
129 border-radius: 8px;
130 font-weight: 500;
131 cursor: pointer;
132 font-size: 13px;
133 transition: all 0.3s;
134 ">Clear Stored Codes</button>
135 <div id="status-message" style="font-size: 12px; margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.15); border-radius: 6px; text-align: center; display: none;"></div>
136 `;
137
138 document.body.appendChild(controlPanel);
139
140 // Add hover effects
141 const extractBtn = document.getElementById('extract-btn');
142 const clearBtn = document.getElementById('clear-codes-btn');
143
144 extractBtn.addEventListener('mouseenter', () => {
145 extractBtn.style.transform = 'translateY(-2px)';
146 extractBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
147 });
148 extractBtn.addEventListener('mouseleave', () => {
149 extractBtn.style.transform = 'translateY(0)';
150 extractBtn.style.boxShadow = 'none';
151 });
152
153 clearBtn.addEventListener('mouseenter', () => {
154 clearBtn.style.background = 'rgba(255,255,255,0.3)';
155 });
156 clearBtn.addEventListener('mouseleave', () => {
157 clearBtn.style.background = 'rgba(255,255,255,0.2)';
158 });
159
160 // Update count on load
161 const storedCodes = await GM.getValue('redPacketCodes', '[]');
162 const codes = JSON.parse(storedCodes);
163 document.getElementById('count-number').textContent = codes.length;
164
165 // Extract button handler
166 extractBtn.addEventListener('click', async () => {
167 extractBtn.disabled = true;
168 extractBtn.textContent = 'Extracting...';
169
170 try {
171 const codes = await extractCodesFromTelegram();
172 document.getElementById('count-number').textContent = codes.length;
173
174 const statusMsg = document.getElementById('status-message');
175 statusMsg.style.display = 'block';
176 statusMsg.style.background = 'rgba(76, 175, 80, 0.3)';
177 statusMsg.textContent = `✓ Extracted ${codes.length} codes successfully!`;
178
179 setTimeout(() => {
180 statusMsg.style.display = 'none';
181 }, 3000);
182 } catch (error) {
183 console.error('Error extracting codes:', error);
184 const statusMsg = document.getElementById('status-message');
185 statusMsg.style.display = 'block';
186 statusMsg.style.background = 'rgba(244, 67, 54, 0.3)';
187 statusMsg.textContent = '✗ Error extracting codes';
188 } finally {
189 extractBtn.disabled = false;
190 extractBtn.textContent = 'Extract Codes';
191 }
192 });
193
194 // Clear button handler
195 clearBtn.addEventListener('click', async () => {
196 await GM.setValue('redPacketCodes', '[]');
197 await GM.deleteValue('currentCodeIndex');
198 document.getElementById('count-number').textContent = '0';
199
200 const statusMsg = document.getElementById('status-message');
201 statusMsg.style.display = 'block';
202 statusMsg.style.background = 'rgba(255, 152, 0, 0.3)';
203 statusMsg.textContent = '✓ All codes cleared';
204
205 setTimeout(() => {
206 statusMsg.style.display = 'none';
207 }, 2000);
208 });
209
210 // Auto-extract on page load
211 await delay(2000);
212 console.log('Auto-extracting codes on page load...');
213 const codes = await extractCodesFromTelegram();
214 document.getElementById('count-number').textContent = codes.length;
215 }
216
217 // ==================== BINANCE FUNCTIONALITY ====================
218 async function claimRedPacketOnBinance() {
219 console.log('Starting Binance red packet claiming process...');
220
221 // Get stored codes
222 const storedCodes = await GM.getValue('redPacketCodes', '[]');
223 const codes = JSON.parse(storedCodes);
224
225 if (codes.length === 0) {
226 console.log('No codes available to claim');
227 return { success: false, message: 'No codes available' };
228 }
229
230 // Get current index
231 let currentIndex = await GM.getValue('currentCodeIndex', 0);
232
233 if (currentIndex >= codes.length) {
234 console.log('All codes have been processed');
235 return { success: false, message: 'All codes claimed' };
236 }
237
238 const currentCode = codes[currentIndex];
239 console.log(`Claiming code ${currentIndex + 1}/${codes.length}: ${currentCode}`);
240
241 try {
242 // Find input field
243 const input = document.querySelector('input[placeholder="Enter red packet code"]');
244 if (!input) {
245 throw new Error('Input field not found');
246 }
247
248 // Clear and enter code
249 input.value = '';
250 input.focus();
251 input.value = currentCode;
252
253 // Trigger input event to enable the button
254 input.dispatchEvent(new Event('input', { bubbles: true }));
255 input.dispatchEvent(new Event('change', { bubbles: true }));
256
257 console.log('Code entered into input field');
258 await delay(500);
259
260 // Find and click Claim button
261 const claimButton = Array.from(document.querySelectorAll('button')).find(btn =>
262 btn.textContent.trim() === 'Claim' &&
263 !btn.classList.contains('inactive') &&
264 btn.getAttribute('aria-disabled') !== 'true'
265 );
266
267 if (!claimButton) {
268 throw new Error('Claim button not found or not enabled');
269 }
270
271 console.log('Clicking Claim button...');
272 claimButton.click();
273
274 // Wait for popup to appear
275 await delay(2000);
276
277 // Look for "Open" button in popup
278 const openButton = Array.from(document.querySelectorAll('button')).find(btn =>
279 btn.textContent.trim() === 'Open'
280 );
281
282 if (openButton) {
283 console.log('Found Open button, clicking...');
284 openButton.click();
285 await delay(2000);
286
287 // Look for close button (X button)
288 const closeButton = document.querySelector('button[aria-label="Close"], button.bn-modal-close, button[class*="close"]');
289 if (closeButton) {
290 console.log('Found close button, clicking...');
291 closeButton.click();
292 await delay(1000);
293 }
294 }
295
296 // Move to next code
297 currentIndex++;
298 await GM.setValue('currentCodeIndex', currentIndex);
299
300 console.log(`Successfully processed code. Moving to next (${currentIndex}/${codes.length})`);
301 return { success: true, message: `Claimed ${currentIndex}/${codes.length}`, currentIndex, total: codes.length };
302
303 } catch (error) {
304 console.error('Error claiming red packet:', error);
305 // Still move to next code even if there's an error
306 currentIndex++;
307 await GM.setValue('currentCodeIndex', currentIndex);
308 return { success: false, message: error.message, currentIndex, total: codes.length };
309 }
310 }
311
312 async function setupBinanceClaimer() {
313 console.log('Setting up Binance auto claimer...');
314
315 // Create control panel
316 const controlPanel = document.createElement('div');
317 controlPanel.id = 'binance-claimer-panel';
318 controlPanel.style.cssText = `
319 position: fixed;
320 top: 80px;
321 right: 20px;
322 background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
323 color: white;
324 padding: 20px;
325 border-radius: 12px;
326 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
327 z-index: 10000;
328 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
329 min-width: 300px;
330 backdrop-filter: blur(10px);
331 `;
332
333 controlPanel.innerHTML = `
334 <div style="font-size: 16px; font-weight: bold; margin-bottom: 15px; display: flex; align-items: center; gap: 8px;">
335 <span style="font-size: 20px;">🎁</span>
336 Auto Claimer
337 </div>
338 <div style="font-size: 13px; margin-bottom: 15px; opacity: 0.9; line-height: 1.4;">
339 Automatically claim red packets one by one
340 </div>
341 <div id="progress-info" style="font-size: 14px; margin-bottom: 15px; padding: 12px; background: rgba(255,255,255,0.2); border-radius: 8px;">
342 <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
343 <span>Progress:</span>
344 <span id="progress-text" style="font-weight: bold;">0/0</span>
345 </div>
346 <div style="width: 100%; height: 8px; background: rgba(255,255,255,0.3); border-radius: 4px; overflow: hidden;">
347 <div id="progress-bar" style="width: 0%; height: 100%; background: white; transition: width 0.3s;"></div>
348 </div>
349 </div>
350 <button id="start-claiming-btn" style="
351 width: 100%;
352 padding: 12px;
353 background: white;
354 color: #f5576c;
355 border: none;
356 border-radius: 8px;
357 font-weight: bold;
358 cursor: pointer;
359 font-size: 14px;
360 transition: all 0.3s;
361 margin-bottom: 10px;
362 ">Start Auto Claiming</button>
363 <button id="stop-claiming-btn" style="
364 width: 100%;
365 padding: 10px;
366 background: rgba(255,255,255,0.2);
367 color: white;
368 border: 1px solid rgba(255,255,255,0.3);
369 border-radius: 8px;
370 font-weight: 500;
371 cursor: pointer;
372 font-size: 13px;
373 transition: all 0.3s;
374 display: none;
375 ">Stop Claiming</button>
376 <button id="reset-progress-btn" style="
377 width: 100%;
378 padding: 10px;
379 background: rgba(255,255,255,0.2);
380 color: white;
381 border: 1px solid rgba(255,255,255,0.3);
382 border-radius: 8px;
383 font-weight: 500;
384 cursor: pointer;
385 font-size: 13px;
386 transition: all 0.3s;
387 ">Reset Progress</button>
388 <div id="claim-status" style="font-size: 12px; margin-top: 12px; padding: 8px; background: rgba(255,255,255,0.15); border-radius: 6px; text-align: center; display: none;"></div>
389 `;
390
391 document.body.appendChild(controlPanel);
392
393 let isClaimingActive = false;
394 let claimingInterval = null;
395
396 const startBtn = document.getElementById('start-claiming-btn');
397 const stopBtn = document.getElementById('stop-claiming-btn');
398 const resetBtn = document.getElementById('reset-progress-btn');
399 const progressText = document.getElementById('progress-text');
400 const progressBar = document.getElementById('progress-bar');
401 const statusDiv = document.getElementById('claim-status');
402
403 // Add hover effects
404 startBtn.addEventListener('mouseenter', () => {
405 startBtn.style.transform = 'translateY(-2px)';
406 startBtn.style.boxShadow = '0 4px 12px rgba(0,0,0,0.2)';
407 });
408 startBtn.addEventListener('mouseleave', () => {
409 startBtn.style.transform = 'translateY(0)';
410 startBtn.style.boxShadow = 'none';
411 });
412
413 // Update progress display
414 async function updateProgress() {
415 const storedCodes = await GM.getValue('redPacketCodes', '[]');
416 const codes = JSON.parse(storedCodes);
417 const currentIndex = await GM.getValue('currentCodeIndex', 0);
418
419 progressText.textContent = `${currentIndex}/${codes.length}`;
420 const percentage = codes.length > 0 ? (currentIndex / codes.length) * 100 : 0;
421 progressBar.style.width = `${percentage}%`;
422 }
423
424 // Initial progress update
425 await updateProgress();
426
427 // Start claiming
428 startBtn.addEventListener('click', async () => {
429 isClaimingActive = true;
430 startBtn.style.display = 'none';
431 stopBtn.style.display = 'block';
432 resetBtn.disabled = true;
433 resetBtn.style.opacity = '0.5';
434
435 statusDiv.style.display = 'block';
436 statusDiv.style.background = 'rgba(33, 150, 243, 0.3)';
437 statusDiv.textContent = '⏳ Auto claiming started...';
438
439 // Claim immediately, then set interval
440 async function claimNext() {
441 if (!isClaimingActive) return;
442
443 const result = await claimRedPacketOnBinance();
444 await updateProgress();
445
446 if (result.success) {
447 statusDiv.style.background = 'rgba(76, 175, 80, 0.3)';
448 statusDiv.textContent = `✓ ${result.message}`;
449 } else {
450 if (result.message === 'All codes claimed') {
451 statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
452 statusDiv.textContent = '✓ All codes have been claimed!';
453 isClaimingActive = false;
454 startBtn.style.display = 'block';
455 stopBtn.style.display = 'none';
456 resetBtn.disabled = false;
457 resetBtn.style.opacity = '1';
458 if (claimingInterval) clearInterval(claimingInterval);
459 } else {
460 statusDiv.style.background = 'rgba(244, 67, 54, 0.3)';
461 statusDiv.textContent = `⚠ Error: ${result.message}`;
462 }
463 }
464 }
465
466 await claimNext();
467 claimingInterval = setInterval(claimNext, 5000); // Claim every 5 seconds
468 });
469
470 // Stop claiming
471 stopBtn.addEventListener('click', () => {
472 isClaimingActive = false;
473 if (claimingInterval) {
474 clearInterval(claimingInterval);
475 claimingInterval = null;
476 }
477 startBtn.style.display = 'block';
478 stopBtn.style.display = 'none';
479 resetBtn.disabled = false;
480 resetBtn.style.opacity = '1';
481
482 statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
483 statusDiv.textContent = '⏸ Claiming stopped';
484 });
485
486 // Reset progress
487 resetBtn.addEventListener('click', async () => {
488 await GM.deleteValue('currentCodeIndex');
489 await updateProgress();
490
491 statusDiv.style.display = 'block';
492 statusDiv.style.background = 'rgba(255, 152, 0, 0.3)';
493 statusDiv.textContent = '✓ Progress reset';
494
495 setTimeout(() => {
496 statusDiv.style.display = 'none';
497 }, 2000);
498 });
499 }
500
501 // ==================== INITIALIZATION ====================
502 async function init() {
503 console.log('Initializing extension...');
504 console.log('Current URL:', window.location.href);
505
506 // Wait for page to be ready
507 await delay(1500);
508
509 if (window.location.href.includes('web.telegram.org')) {
510 console.log('Running on Telegram');
511 await setupTelegramExtractor();
512 } else if (window.location.href.includes('binance.com/en/my/wallet/account/payment/cryptobox')) {
513 console.log('Running on Binance');
514 await setupBinanceClaimer();
515 }
516 }
517
518 // Start the extension
519 if (document.readyState === 'loading') {
520 document.addEventListener('DOMContentLoaded', init);
521 } else {
522 init();
523 }
524})();