Automatically collects red packet codes from one channel and pastes them in another
Size
7.5 KB
Version
1.0.1
Created
Nov 5, 2025
Updated
8 days ago
1// ==UserScript==
2// @name Binance Red Packet Code Collector
3// @description Automatically collects red packet codes from one channel and pastes them in another
4// @version 1.0.1
5// @match https://web.telegram.org/*
6// @match https://t.me/*
7// @icon https://web.telegram.org/k/assets/img/favicon.ico?v=jw3mK7G9Ry
8// ==/UserScript==
9(function() {
10 'use strict';
11
12 // Configuration
13 const SOURCE_CHANNEL = 'binance_red_packetz'; // Channel to collect codes from
14 const TARGET_CHANNEL = '+xYjnHNvEyQIyMzZl'; // Channel to paste codes to
15 const CODE_PATTERN = /\b[A-Z0-9]{8}\b/g; // Pattern to match red packet codes
16
17 console.log('Binance Red Packet Code Collector initialized');
18
19 // Debounce function to prevent excessive calls
20 function debounce(func, wait) {
21 let timeout;
22 return function executedFunction(...args) {
23 const later = () => {
24 clearTimeout(timeout);
25 func(...args);
26 };
27 clearTimeout(timeout);
28 timeout = setTimeout(later, wait);
29 };
30 }
31
32 // Get current channel identifier from URL
33 function getCurrentChannel() {
34 const url = window.location.href;
35 if (url.includes('@binance_red_packetz') || url.includes('binance_red_packetz')) {
36 return 'source';
37 } else if (url.includes('+xYjnHNvEyQIyMzZl') || url.includes('xYjnHNvEyQIyMzZl')) {
38 return 'target';
39 }
40 return null;
41 }
42
43 // Extract codes from messages
44 async function extractCodesFromMessages() {
45 const channel = getCurrentChannel();
46 if (channel !== 'source') {
47 console.log('Not on source channel, skipping code extraction');
48 return;
49 }
50
51 console.log('Scanning for red packet codes...');
52
53 // Find all code elements in messages
54 const codeElements = document.querySelectorAll('code.monospace-text');
55 const newCodes = [];
56
57 for (const codeElement of codeElements) {
58 const codeText = codeElement.textContent.trim();
59
60 // Check if it matches the pattern
61 if (CODE_PATTERN.test(codeText)) {
62 console.log('Found potential code:', codeText);
63
64 // Check if we've already collected this code
65 const collectedCodes = await GM.getValue('collectedCodes', []);
66 if (!collectedCodes.includes(codeText)) {
67 newCodes.push(codeText);
68 collectedCodes.push(codeText);
69 await GM.setValue('collectedCodes', collectedCodes);
70 console.log('New code collected:', codeText);
71 }
72 }
73 }
74
75 if (newCodes.length > 0) {
76 console.log(`Collected ${newCodes.length} new codes:`, newCodes);
77
78 // Get pending codes to paste
79 const pendingCodes = await GM.getValue('pendingCodes', []);
80 const updatedPending = [...pendingCodes, ...newCodes];
81 await GM.setValue('pendingCodes', updatedPending);
82
83 console.log('Total pending codes to paste:', updatedPending.length);
84 }
85 }
86
87 // Paste codes in target channel
88 async function pasteCodesInTarget() {
89 const channel = getCurrentChannel();
90 if (channel !== 'target') {
91 console.log('Not on target channel, skipping paste');
92 return;
93 }
94
95 const pendingCodes = await GM.getValue('pendingCodes', []);
96 if (pendingCodes.length === 0) {
97 console.log('No pending codes to paste');
98 return;
99 }
100
101 console.log(`Attempting to paste ${pendingCodes.length} codes...`);
102
103 // Find the message input field
104 const inputField = document.querySelector('.input-message-input[data-peer-id]');
105 if (!inputField) {
106 console.error('Could not find message input field');
107 return;
108 }
109
110 // Paste one code at a time with delay
111 for (let i = 0; i < pendingCodes.length; i++) {
112 const code = pendingCodes[i];
113
114 // Set the text in the input field
115 inputField.textContent = code;
116 inputField.classList.remove('is-empty');
117
118 // Trigger input event
119 const inputEvent = new Event('input', { bubbles: true });
120 inputField.dispatchEvent(inputEvent);
121
122 console.log(`Pasted code ${i + 1}/${pendingCodes.length}: ${code}`);
123
124 // Wait a bit before sending
125 await new Promise(resolve => setTimeout(resolve, 1000));
126
127 // Find and click the send button
128 const sendButton = document.querySelector('.btn-send');
129 if (sendButton) {
130 sendButton.click();
131 console.log('Send button clicked for code:', code);
132
133 // Wait before next code
134 await new Promise(resolve => setTimeout(resolve, 2000));
135 } else {
136 console.error('Could not find send button');
137 }
138 }
139
140 // Clear pending codes after pasting
141 await GM.setValue('pendingCodes', []);
142 console.log('All codes pasted successfully');
143 }
144
145 // Monitor for new messages
146 function observeMessages() {
147 const channel = getCurrentChannel();
148 if (!channel) {
149 console.log('Not on a monitored channel');
150 return;
151 }
152
153 console.log(`Monitoring channel: ${channel}`);
154
155 // Find the messages container
156 const messagesContainer = document.querySelector('.bubbles-inner');
157 if (!messagesContainer) {
158 console.log('Messages container not found, will retry...');
159 setTimeout(observeMessages, 2000);
160 return;
161 }
162
163 // Create observer for new messages
164 const observer = new MutationObserver(debounce(async (mutations) => {
165 console.log('DOM changes detected');
166
167 if (channel === 'source') {
168 await extractCodesFromMessages();
169 } else if (channel === 'target') {
170 await pasteCodesInTarget();
171 }
172 }, 1000));
173
174 observer.observe(messagesContainer, {
175 childList: true,
176 subtree: true
177 });
178
179 console.log('Observer started for messages');
180
181 // Initial scan
182 if (channel === 'source') {
183 extractCodesFromMessages();
184 } else if (channel === 'target') {
185 pasteCodesInTarget();
186 }
187 }
188
189 // Initialize the extension
190 async function init() {
191 console.log('Starting Binance Red Packet Code Collector...');
192
193 // Wait for page to load
194 if (document.readyState === 'loading') {
195 document.addEventListener('DOMContentLoaded', init);
196 return;
197 }
198
199 // Wait a bit for Telegram to fully load
200 setTimeout(() => {
201 observeMessages();
202 }, 3000);
203
204 // Also check when URL changes (navigation between channels)
205 let lastUrl = window.location.href;
206 setInterval(() => {
207 const currentUrl = window.location.href;
208 if (currentUrl !== lastUrl) {
209 console.log('URL changed, reinitializing...');
210 lastUrl = currentUrl;
211 setTimeout(() => {
212 observeMessages();
213 }, 2000);
214 }
215 }, 1000);
216 }
217
218 // Start the extension
219 init();
220})();