Size
15.1 KB
Version
1.0.1
Created
Mar 21, 2026
Updated
about 5 hours ago
1// ==UserScript==
2// @name Vie Faucet Shortlink Auto-Solver
3// @description A new extension
4// @version 1.0.1
5// @match https://*.viefaucet.com/*
6// @match https://*/*
7// @icon https://viefaucet.com/favicon.ico
8// @grant GM.getValue
9// @grant GM.setValue
10// @grant GM.openInTab
11// ==/UserScript==
12(function() {
13 'use strict';
14
15 console.log('Vie Faucet Shortlink Auto-Solver loaded');
16
17 // Debounce function to prevent excessive calls
18 function debounce(func, wait) {
19 let timeout;
20 return function executedFunction(...args) {
21 const later = () => {
22 clearTimeout(timeout);
23 func(...args);
24 };
25 clearTimeout(timeout);
26 timeout = setTimeout(later, wait);
27 };
28 }
29
30 // Check if we're on the Vie Faucet shortlink page
31 function isVieFaucetPage() {
32 return window.location.hostname.includes('viefaucet.com') &&
33 window.location.pathname.includes('/app/link');
34 }
35
36 // Check if we're on a shortlink destination page
37 function isShortlinkPage() {
38 return !window.location.hostname.includes('viefaucet.com');
39 }
40
41 // ===== VIE FAUCET PAGE AUTOMATION =====
42 async function handleVieFaucetPage() {
43 console.log('Running Vie Faucet page automation');
44
45 // Get automation state
46 const autoSolveEnabled = await GM.getValue('autoSolveEnabled', false);
47
48 // Create control panel
49 createControlPanel();
50
51 if (!autoSolveEnabled) {
52 console.log('Auto-solve is disabled');
53 return;
54 }
55
56 // Find and click available shortlinks
57 const shortlinks = document.querySelectorAll('.shortlink');
58 console.log(`Found ${shortlinks.length} shortlinks`);
59
60 for (const card of shortlinks) {
61 const claimBtn = card.querySelector('button.el-button--success:not([aria-disabled="true"])');
62 const nameEl = card.querySelector('.link-name');
63 const linkName = nameEl ? nameEl.textContent.trim() : 'Unknown';
64
65 if (claimBtn && claimBtn.getAttribute('aria-disabled') !== 'true') {
66 // Check if we've already processed this link recently
67 const lastProcessed = await GM.getValue(`lastProcessed_${linkName}`, 0);
68 const now = Date.now();
69
70 // Wait at least 30 seconds between processing the same link
71 if (now - lastProcessed < 30000) {
72 console.log(`Skipping ${linkName} - processed recently`);
73 continue;
74 }
75
76 console.log(`Clicking claim button for: ${linkName}`);
77 await GM.setValue(`lastProcessed_${linkName}`, now);
78 await GM.setValue('currentShortlink', linkName);
79
80 claimBtn.click();
81
82 // Wait a bit before processing next link
83 await new Promise(resolve => setTimeout(resolve, 3000));
84 break; // Process one at a time
85 }
86 }
87 }
88
89 // Create control panel for Vie Faucet page
90 function createControlPanel() {
91 if (document.getElementById('vie-auto-solver-panel')) return;
92
93 const panel = document.createElement('div');
94 panel.id = 'vie-auto-solver-panel';
95 panel.style.cssText = `
96 position: fixed;
97 top: 80px;
98 right: 20px;
99 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
100 color: white;
101 padding: 15px 20px;
102 border-radius: 12px;
103 box-shadow: 0 4px 15px rgba(0,0,0,0.3);
104 z-index: 999999;
105 font-family: Arial, sans-serif;
106 min-width: 250px;
107 `;
108
109 GM.getValue('autoSolveEnabled', false).then(enabled => {
110 panel.innerHTML = `
111 <div style="font-weight: bold; font-size: 16px; margin-bottom: 10px; display: flex; align-items: center;">
112 <span style="margin-right: 8px;">π€</span> Auto-Solver
113 </div>
114 <div style="margin-bottom: 10px; font-size: 13px; opacity: 0.9;">
115 Status: <span id="solver-status">${enabled ? 'β
Active' : 'βΈοΈ Paused'}</span>
116 </div>
117 <button id="toggle-auto-solve" style="
118 width: 100%;
119 padding: 10px;
120 background: white;
121 color: #667eea;
122 border: none;
123 border-radius: 8px;
124 font-weight: bold;
125 cursor: pointer;
126 font-size: 14px;
127 transition: all 0.3s;
128 ">
129 ${enabled ? 'Pause' : 'Start'} Auto-Solve
130 </button>
131 <div style="margin-top: 10px; font-size: 11px; opacity: 0.8; text-align: center;">
132 Processed: <span id="processed-count">0</span>
133 </div>
134 `;
135
136 const toggleBtn = panel.querySelector('#toggle-auto-solve');
137 toggleBtn.addEventListener('mouseenter', () => {
138 toggleBtn.style.transform = 'scale(1.05)';
139 });
140 toggleBtn.addEventListener('mouseleave', () => {
141 toggleBtn.style.transform = 'scale(1)';
142 });
143 toggleBtn.addEventListener('click', async () => {
144 const currentState = await GM.getValue('autoSolveEnabled', false);
145 const newState = !currentState;
146 await GM.setValue('autoSolveEnabled', newState);
147
148 const statusEl = panel.querySelector('#solver-status');
149 statusEl.textContent = newState ? 'β
Active' : 'βΈοΈ Paused';
150 toggleBtn.textContent = newState ? 'Pause Auto-Solve' : 'Start Auto-Solve';
151
152 console.log(`Auto-solve ${newState ? 'enabled' : 'disabled'}`);
153
154 if (newState) {
155 setTimeout(() => handleVieFaucetPage(), 1000);
156 }
157 });
158
159 document.body.appendChild(panel);
160
161 // Update processed count
162 GM.getValue('processedCount', 0).then(count => {
163 const countEl = panel.querySelector('#processed-count');
164 if (countEl) countEl.textContent = count;
165 });
166 });
167 }
168
169 // ===== SHORTLINK PAGE AUTOMATION =====
170 async function handleShortlinkPage() {
171 console.log('Running shortlink page automation');
172
173 const currentShortlink = await GM.getValue('currentShortlink', 'Unknown');
174 console.log(`Processing shortlink: ${currentShortlink}`);
175
176 // Create status indicator
177 createShortlinkStatus();
178
179 // Wait for page to load
180 await new Promise(resolve => setTimeout(resolve, 3000));
181
182 // Try to find and handle common shortlink elements
183 await findAndClickButtons();
184
185 // Set up mutation observer to watch for new buttons
186 setupMutationObserver();
187 }
188
189 // Create status indicator for shortlink pages
190 function createShortlinkStatus() {
191 if (document.getElementById('vie-shortlink-status')) return;
192
193 const status = document.createElement('div');
194 status.id = 'vie-shortlink-status';
195 status.style.cssText = `
196 position: fixed;
197 top: 10px;
198 right: 10px;
199 background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
200 color: white;
201 padding: 12px 18px;
202 border-radius: 10px;
203 box-shadow: 0 4px 12px rgba(0,0,0,0.3);
204 z-index: 999999;
205 font-family: Arial, sans-serif;
206 font-size: 13px;
207 font-weight: bold;
208 `;
209 status.innerHTML = 'π Auto-solving shortlink...';
210 document.body.appendChild(status);
211 }
212
213 // Update status message
214 function updateStatus(message) {
215 const status = document.getElementById('vie-shortlink-status');
216 if (status) {
217 status.innerHTML = message;
218 }
219 }
220
221 // Find and click buttons on shortlink pages
222 async function findAndClickButtons() {
223 console.log('Searching for buttons to click...');
224
225 // Common button selectors for shortlink sites
226 const buttonSelectors = [
227 // Generic continue/next buttons
228 'button[type="submit"]:not([disabled])',
229 'button:not([disabled]):not([aria-disabled="true"])',
230 'a.btn:not(.disabled)',
231 'input[type="submit"]:not([disabled])',
232
233 // Common shortlink button classes
234 '.btn-primary:not([disabled])',
235 '.btn-success:not([disabled])',
236 '.continue-button:not([disabled])',
237 '.next-button:not([disabled])',
238 '.get-link:not([disabled])',
239 '.verify-button:not([disabled])',
240
241 // Specific shortlink sites
242 '#invisibleCaptchaShortlink',
243 '#link-view',
244 '#btn-main',
245 '#proceed',
246 '#getlink',
247 '#gotolink'
248 ];
249
250 // Look for countdown timers
251 const timerSelectors = [
252 '#timer', '#countdown', '.timer', '.countdown',
253 '[id*="timer"]', '[class*="timer"]',
254 '[id*="countdown"]', '[class*="countdown"]'
255 ];
256
257 // Check for timers first
258 for (const selector of timerSelectors) {
259 const timer = document.querySelector(selector);
260 if (timer) {
261 const timerText = timer.textContent.trim();
262 console.log(`Found timer: ${timerText}`);
263 updateStatus(`β³ Waiting for timer: ${timerText}`);
264
265 // Extract seconds from timer
266 const seconds = extractSeconds(timerText);
267 if (seconds > 0 && seconds < 300) { // Max 5 minutes
268 console.log(`Waiting ${seconds} seconds for timer...`);
269 await new Promise(resolve => setTimeout(resolve, (seconds + 2) * 1000));
270 }
271 }
272 }
273
274 // Try to find and click buttons
275 for (const selector of buttonSelectors) {
276 const buttons = document.querySelectorAll(selector);
277
278 for (const button of buttons) {
279 const buttonText = button.textContent.trim().toLowerCase();
280 const isVisible = button.offsetParent !== null;
281
282 // Skip hidden buttons or buttons with certain text
283 if (!isVisible) continue;
284 if (buttonText.includes('close') || buttonText.includes('cancel')) continue;
285
286 // Look for promising button text
287 const goodKeywords = ['continue', 'next', 'proceed', 'get link', 'verify', 'free access', 'click here', 'go to link'];
288 const hasGoodKeyword = goodKeywords.some(keyword => buttonText.includes(keyword));
289
290 if (hasGoodKeyword || buttonText === '' || button.tagName === 'INPUT') {
291 console.log(`Clicking button: ${buttonText || selector}`);
292 updateStatus(`β
Clicking: ${buttonText || 'button'}`);
293
294 button.click();
295 await new Promise(resolve => setTimeout(resolve, 2000));
296
297 // Check if we've been redirected or if new content appeared
298 const currentUrl = window.location.href;
299 console.log(`Current URL after click: ${currentUrl}`);
300
301 return true;
302 }
303 }
304 }
305
306 // Check if we've reached the final destination
307 if (await checkIfCompleted()) {
308 console.log('Shortlink completed!');
309 updateStatus('β
Completed!');
310
311 // Increment processed count
312 const count = await GM.getValue('processedCount', 0);
313 await GM.setValue('processedCount', count + 1);
314
315 // Close tab after a delay
316 setTimeout(() => {
317 window.close();
318 }, 3000);
319
320 return true;
321 }
322
323 return false;
324 }
325
326 // Extract seconds from timer text
327 function extractSeconds(text) {
328 // Try to match patterns like "10", "0:10", "00:10", "10s", etc.
329 const patterns = [
330 /(\d+)\s*s/i, // "10s" or "10 seconds"
331 /(\d+):(\d+)/, // "0:10" or "00:10"
332 /(\d+)/ // Just "10"
333 ];
334
335 for (const pattern of patterns) {
336 const match = text.match(pattern);
337 if (match) {
338 if (match[2]) {
339 // Minutes:seconds format
340 return parseInt(match[1]) * 60 + parseInt(match[2]);
341 } else {
342 return parseInt(match[1]);
343 }
344 }
345 }
346
347 return 0;
348 }
349
350 // Check if shortlink is completed
351 async function checkIfCompleted() {
352 // Check if we're back on Vie Faucet
353 if (window.location.hostname.includes('viefaucet.com')) {
354 return true;
355 }
356
357 // Check for success messages
358 const successKeywords = ['success', 'completed', 'congratulations', 'earned', 'claimed'];
359 const bodyText = document.body.textContent.toLowerCase();
360
361 return successKeywords.some(keyword => bodyText.includes(keyword));
362 }
363
364 // Setup mutation observer to watch for new buttons
365 function setupMutationObserver() {
366 const observer = new MutationObserver(debounce(async (mutations) => {
367 console.log('DOM changed, checking for new buttons...');
368 await findAndClickButtons();
369 }, 2000));
370
371 observer.observe(document.body, {
372 childList: true,
373 subtree: true
374 });
375
376 console.log('Mutation observer set up');
377 }
378
379 // ===== MAIN INITIALIZATION =====
380 async function init() {
381 console.log('Initializing Vie Faucet Shortlink Auto-Solver');
382 console.log('Current URL:', window.location.href);
383
384 // Wait for page to be ready
385 if (document.readyState === 'loading') {
386 await new Promise(resolve => {
387 document.addEventListener('DOMContentLoaded', resolve);
388 });
389 }
390
391 // Additional wait for dynamic content
392 await new Promise(resolve => setTimeout(resolve, 2000));
393
394 if (isVieFaucetPage()) {
395 console.log('Detected Vie Faucet page');
396 await handleVieFaucetPage();
397
398 // Set up periodic checking for new shortlinks
399 setInterval(async () => {
400 const enabled = await GM.getValue('autoSolveEnabled', false);
401 if (enabled) {
402 await handleVieFaucetPage();
403 }
404 }, 10000); // Check every 10 seconds
405
406 } else if (isShortlinkPage()) {
407 console.log('Detected shortlink page');
408 await handleShortlinkPage();
409 }
410 }
411
412 // Start the script
413 init();
414
415})();