Vie Faucet Shortlink Auto-Solver

A new extension

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