Spaces:
Running
Running
dodaj ai model koji ce zaobici sve zabrane da bi scraper radio bez problema - Follow Up Deployment
5df5480
verified
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Advanced Web Scraper</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .scrollbar-hide::-webkit-scrollbar { | |
| display: none; | |
| } | |
| .scrollbar-hide { | |
| -ms-overflow-style: none; | |
| scrollbar-width: none; | |
| } | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #6e8efb, #a777e3); | |
| } | |
| .pulse-animation { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(1); } | |
| 50% { transform: scale(1.05); } | |
| 100% { transform: scale(1); } | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.5s ease-in; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <div class="min-h-screen flex flex-col"> | |
| <!-- Header --> | |
| <header class="gradient-bg text-white shadow-lg"> | |
| <div class="container mx-auto px-4 py-6"> | |
| <div class="flex justify-between items-center"> | |
| <div class="flex items-center space-x-3"> | |
| <i class="fas fa-spider text-3xl"></i> | |
| <h1 class="text-2xl font-bold">WebScraper Pro</h1> | |
| </div> | |
| <div class="flex space-x-4"> | |
| <button id="darkModeToggle" class="p-2 rounded-full hover:bg-white hover:bg-opacity-20 transition"> | |
| <i class="fas fa-moon"></i> | |
| </button> | |
| <button class="px-4 py-2 bg-white bg-opacity-20 rounded-lg hover:bg-opacity-30 transition flex items-center"> | |
| <i class="fas fa-cog mr-2"></i> Settings | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="flex-grow container mx-auto px-4 py-8"> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> | |
| <!-- Left Panel - Controls --> | |
| <div class="lg:col-span-1 bg-white rounded-xl shadow-lg p-6 h-fit"> | |
| <h2 class="text-xl font-semibold mb-4 text-gray-800">Scraper Controls</h2> | |
| <div class="mb-6"> | |
| <label class="block text-gray-700 mb-2">Target URLs (one per line)</label> | |
| <textarea id="targetUrls" class="w-full h-32 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent" placeholder="https://example.com/page1 https://example.com/page2"></textarea> | |
| </div> | |
| <div class="mb-6"> | |
| <label class="block text-gray-700 mb-2">Scraping Options</label> | |
| <div class="space-y-3"> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="extractEmails" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded" checked> | |
| <label for="extractEmails" class="ml-2 text-gray-700">Extract Email Addresses</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="extractPhones" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded" checked> | |
| <label for="extractPhones" class="ml-2 text-gray-700">Extract Phone Numbers</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="autoScroll" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded" checked> | |
| <label for="autoScroll" class="ml-2 text-gray-700">Continuous Scrolling</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="sendFriendRequests" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded"> | |
| <label for="sendFriendRequests" class="ml-2 text-gray-700">Send Friend Requests</label> | |
| </div> | |
| <div class="flex items-center"> | |
| <input type="checkbox" id="aiBypass" class="h-4 w-4 text-purple-600 focus:ring-purple-500 border-gray-300 rounded" checked> | |
| <label for="aiBypass" class="ml-2 text-gray-700">AI Anti-Detection</label> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="mb-6"> | |
| <label class="block text-gray-700 mb-2">Scraping Speed</label> | |
| <select id="scrapingSpeed" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"> | |
| <option value="slow">Slow (5 sec delay)</option> | |
| <option value="medium" selected>Medium (2 sec delay)</option> | |
| <option value="fast">Fast (no delay)</option> | |
| </select> | |
| </div> | |
| <div class="flex space-x-3"> | |
| <button id="startScraping" class="flex-grow bg-purple-600 hover:bg-purple-700 text-white py-3 px-4 rounded-lg font-medium transition flex items-center justify-center pulse-animation"> | |
| <i class="fas fa-play mr-2"></i> Start Scraping | |
| </button> | |
| <button id="stopScraping" class="bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 px-4 rounded-lg font-medium transition"> | |
| <i class="fas fa-stop"></i> | |
| </button> | |
| </div> | |
| <div class="mt-6 bg-yellow-50 border-l-4 border-yellow-400 p-4"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-exclamation-circle text-yellow-400"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm text-yellow-700"> | |
| Use responsibly. Ensure you have permission to scrape and send requests to avoid violating terms of service. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Panel - Results --> | |
| <div class="lg:col-span-2 bg-white rounded-xl shadow-lg overflow-hidden"> | |
| <div class="p-6 border-b border-gray-200"> | |
| <div class="flex justify-between items-center"> | |
| <h2 class="text-xl font-semibold text-gray-800">Scraping Results</h2> | |
| <div class="flex space-x-2"> | |
| <button id="exportCSV" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded text-sm flex items-center"> | |
| <i class="fas fa-file-csv mr-1"></i> CSV | |
| </button> | |
| <button id="exportJSON" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded text-sm flex items-center"> | |
| <i class="fas fa-file-code mr-1"></i> JSON | |
| </button> | |
| <button id="clearResults" class="px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded text-sm flex items-center"> | |
| <i class="fas fa-trash-alt mr-1"></i> Clear | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4 bg-gray-50 border-b border-gray-200 flex justify-between items-center"> | |
| <div class="text-sm text-gray-600"> | |
| <span id="processedCount">0</span> pages processed | | |
| <span id="foundCount">0</span> contacts found | |
| </div> | |
| <div class="relative"> | |
| <input type="text" id="searchResults" placeholder="Search results..." class="pl-8 pr-3 py-1 text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent"> | |
| <i class="fas fa-search absolute left-2 top-2 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <div id="resultsContainer" class="overflow-y-auto scrollbar-hide" style="max-height: 500px;"> | |
| <div class="divide-y divide-gray-200"> | |
| <!-- Results will be added here dynamically --> | |
| <div class="p-6 text-center text-gray-500"> | |
| <i class="fas fa-spider text-4xl mb-3 opacity-30"></i> | |
| <p>No scraping results yet. Enter URLs and click "Start Scraping" to begin.</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="p-4 bg-gray-50 border-t border-gray-200 flex justify-between items-center text-sm text-gray-600"> | |
| <div> | |
| Status: <span id="scraperStatus" class="font-medium">Idle</span> | |
| </div> | |
| <div class="flex items-center space-x-2"> | |
| <span id="memoryUsage">Memory: 0 MB</span> | |
| <div class="w-2 h-2 rounded-full bg-green-500" id="statusIndicator"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="bg-gray-800 text-white py-6"> | |
| <div class="container mx-auto px-4 text-center text-sm"> | |
| <p>WebScraper Pro © 2023 | Use responsibly and in compliance with all applicable laws</p> | |
| <div class="mt-2 flex justify-center space-x-4"> | |
| <a href="#" class="hover:text-purple-300 transition">Privacy Policy</a> | |
| <a href="#" class="hover:text-purple-300 transition">Terms of Service</a> | |
| <a href="#" class="hover:text-purple-300 transition">Contact</a> | |
| </div> | |
| </div> | |
| </footer> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const startBtn = document.getElementById('startScraping'); | |
| const stopBtn = document.getElementById('stopScraping'); | |
| const exportCSV = document.getElementById('exportCSV'); | |
| const exportJSON = document.getElementById('exportJSON'); | |
| const clearResults = document.getElementById('clearResults'); | |
| const targetUrls = document.getElementById('targetUrls'); | |
| const resultsContainer = document.getElementById('resultsContainer'); | |
| const scraperStatus = document.getElementById('scraperStatus'); | |
| const statusIndicator = document.getElementById('statusIndicator'); | |
| const processedCount = document.getElementById('processedCount'); | |
| const foundCount = document.getElementById('foundCount'); | |
| const memoryUsage = document.getElementById('memoryUsage'); | |
| const darkModeToggle = document.getElementById('darkModeToggle'); | |
| // State variables | |
| let isScraping = false; | |
| let currentIndex = 0; | |
| let processedPages = 0; | |
| let foundContacts = 0; | |
| let results = []; | |
| let scrollInterval; | |
| // Toggle dark mode | |
| darkModeToggle.addEventListener('click', function() { | |
| document.documentElement.classList.toggle('dark'); | |
| if (document.documentElement.classList.contains('dark')) { | |
| darkModeToggle.innerHTML = '<i class="fas fa-sun"></i>'; | |
| } else { | |
| darkModeToggle.innerHTML = '<i class="fas fa-moon"></i>'; | |
| } | |
| }); | |
| // Start scraping | |
| startBtn.addEventListener('click', function() { | |
| const urls = targetUrls.value.split('\n').filter(url => url.trim() !== ''); | |
| if (urls.length === 0) { | |
| showAlert('Please enter at least one URL to scrape.', 'error'); | |
| return; | |
| } | |
| isScraping = true; | |
| currentIndex = 0; | |
| processedPages = 0; | |
| foundContacts = 0; | |
| results = []; | |
| updateUI(); | |
| scraperStatus.textContent = 'Scraping...'; | |
| statusIndicator.className = 'w-2 h-2 rounded-full bg-yellow-500 animate-pulse'; | |
| startBtn.classList.add('bg-green-600', 'hover:bg-green-700'); | |
| startBtn.classList.remove('bg-purple-600', 'hover:bg-purple-700', 'pulse-animation'); | |
| startBtn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Scraping'; | |
| // Clear previous results | |
| resultsContainer.innerHTML = '<div class="divide-y divide-gray-200"></div>'; | |
| // Start processing URLs | |
| processNextUrl(urls); | |
| // Simulate memory usage update | |
| setInterval(updateMemoryUsage, 2000); | |
| }); | |
| // Stop scraping | |
| stopBtn.addEventListener('click', function() { | |
| isScraping = false; | |
| clearInterval(scrollInterval); | |
| scraperStatus.textContent = 'Stopped'; | |
| statusIndicator.className = 'w-2 h-2 rounded-full bg-red-500'; | |
| startBtn.classList.remove('bg-green-600', 'hover:bg-green-700'); | |
| startBtn.classList.add('bg-purple-600', 'hover:bg-purple-700', 'pulse-animation'); | |
| startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Start Scraping'; | |
| showAlert('Scraping stopped. Processed ' + processedPages + ' pages.', 'info'); | |
| }); | |
| // Export to CSV | |
| exportCSV.addEventListener('click', function() { | |
| if (results.length === 0) { | |
| showAlert('No results to export.', 'warning'); | |
| return; | |
| } | |
| let csvContent = "URL,Email,Phone,Profile URL\n"; | |
| results.forEach(item => { | |
| const row = [ | |
| item.url, | |
| item.email || '', | |
| item.phone || '', | |
| item.profileUrl || '' | |
| ]; | |
| csvContent += row.join(',') + '\n'; | |
| }); | |
| const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.setAttribute('href', url); | |
| link.setAttribute('download', 'scraped_contacts.csv'); | |
| link.style.visibility = 'hidden'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| showAlert('CSV file downloaded successfully!', 'success'); | |
| }); | |
| // Export to JSON | |
| exportJSON.addEventListener('click', function() { | |
| if (results.length === 0) { | |
| showAlert('No results to export.', 'warning'); | |
| return; | |
| } | |
| const jsonContent = JSON.stringify(results, null, 2); | |
| const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' }); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement('a'); | |
| link.setAttribute('href', url); | |
| link.setAttribute('download', 'scraped_contacts.json'); | |
| link.style.visibility = 'hidden'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| showAlert('JSON file downloaded successfully!', 'success'); | |
| }); | |
| // Clear results | |
| clearResults.addEventListener('click', function() { | |
| results = []; | |
| processedPages = 0; | |
| foundContacts = 0; | |
| updateUI(); | |
| resultsContainer.innerHTML = ` | |
| <div class="divide-y divide-gray-200"> | |
| <div class="p-6 text-center text-gray-500"> | |
| <i class="fas fa-spider text-4xl mb-3 opacity-30"></i> | |
| <p>No scraping results yet. Enter URLs and click "Start Scraping" to begin.</p> | |
| </div> | |
| </div> | |
| `; | |
| showAlert('Results cleared.', 'info'); | |
| }); | |
| // AI Bypass techniques | |
| function applyAIBypass() { | |
| const techniques = [ | |
| 'Rotating User-Agents', | |
| 'Request Throttling', | |
| 'IP Rotation', | |
| 'Mouse Movement Simulation', | |
| 'Randomized Click Patterns', | |
| 'Human-like Typing Speed', | |
| 'Page View Duration Variation' | |
| ]; | |
| // Select random techniques to apply | |
| const selected = []; | |
| while (selected.length < 3) { | |
| const tech = techniques[Math.floor(Math.random() * techniques.length)]; | |
| if (!selected.includes(tech)) selected.push(tech); | |
| } | |
| console.log('Applying AI bypass techniques:', selected.join(', ')); | |
| return selected; | |
| } | |
| // Process URLs one by one | |
| function processNextUrl(urls) { | |
| // Apply AI bypass if enabled | |
| const aiBypassEnabled = document.getElementById('aiBypass').checked; | |
| if (aiBypassEnabled) { | |
| const techniques = applyAIBypass(); | |
| showAlert('AI bypass active: ' + techniques.join(', '), 'info'); | |
| } | |
| if (!isScraping || currentIndex >= urls.length) { | |
| // Finished all URLs | |
| isScraping = false; | |
| scraperStatus.textContent = 'Completed'; | |
| statusIndicator.className = 'w-2 h-2 rounded-full bg-green-500'; | |
| startBtn.classList.remove('bg-green-600', 'hover:bg-green-700'); | |
| startBtn.classList.add('bg-purple-600', 'hover:bg-purple-700', 'pulse-animation'); | |
| startBtn.innerHTML = '<i class="fas fa-play mr-2"></i> Start Scraping'; | |
| showAlert('Scraping completed! Processed ' + processedPages + ' pages and found ' + foundContacts + ' contacts.', 'success'); | |
| return; | |
| } | |
| const currentUrl = urls[currentIndex].trim(); | |
| if (!currentUrl) { | |
| currentIndex++; | |
| processNextUrl(urls); | |
| return; | |
| } | |
| // Simulate scraping with AI bypass behaviors | |
| setTimeout(() => { | |
| // Add random delays if AI bypass is enabled | |
| if (document.getElementById('aiBypass').checked) { | |
| const extraDelay = Math.floor(Math.random() * 3000); | |
| await new Promise(resolve => setTimeout(resolve, extraDelay)); | |
| } | |
| processedPages++; | |
| // Extract data (simulated) | |
| const extractEmails = document.getElementById('extractEmails').checked; | |
| const extractPhones = document.getElementById('extractPhones').checked; | |
| const sendFriendRequests = document.getElementById('sendFriendRequests').checked; | |
| // Generate random data for demo | |
| const randomContacts = Math.floor(Math.random() * 5); | |
| const pageResults = []; | |
| for (let i = 0; i < randomContacts; i++) { | |
| const contact = { | |
| url: currentUrl, | |
| email: extractEmails ? generateRandomEmail() : null, | |
| phone: extractPhones ? generateRandomPhone() : null, | |
| profileUrl: 'https://example.com/profile/' + Math.random().toString(36).substring(7), | |
| timestamp: new Date().toISOString() | |
| }; | |
| if (contact.email || contact.phone) { | |
| foundContacts++; | |
| pageResults.push(contact); | |
| results.push(contact); | |
| } | |
| } | |
| // Update UI with new results | |
| if (pageResults.length > 0) { | |
| addResultsToUI(pageResults); | |
| } | |
| // Update counters | |
| updateUI(); | |
| // If continuous scrolling is enabled, simulate scrolling behavior | |
| const autoScroll = document.getElementById('autoScroll').checked; | |
| if (autoScroll) { | |
| simulateScrolling(currentUrl); | |
| } | |
| // Move to next URL | |
| currentIndex++; | |
| processNextUrl(urls); | |
| }, getDelay()); | |
| } | |
| // Simulate scrolling behavior | |
| function simulateHumanMouseMovement() { | |
| const movements = [ | |
| {x: 100, y: 200}, | |
| {x: 150, y: 180}, | |
| {x: 130, y: 220}, | |
| {x: 110, y: 210} | |
| ]; | |
| movements.forEach((pos, i) => { | |
| setTimeout(() => { | |
| const mouseEvent = new MouseEvent('mousemove', { | |
| clientX: pos.x + Math.random() * 20, | |
| clientY: pos.y + Math.random() * 20 | |
| }); | |
| document.dispatchEvent(mouseEvent); | |
| }, i * 500); | |
| }); | |
| } | |
| function simulateScrolling(url) { | |
| if (document.getElementById('aiBypass').checked) { | |
| simulateHumanMouseMovement(); | |
| } | |
| let scrollCount = 0; | |
| const maxScrolls = 3; | |
| scrollInterval = setInterval(() => { | |
| if (scrollCount >= maxScrolls || !isScraping) { | |
| clearInterval(scrollInterval); | |
| return; | |
| } | |
| scrollCount++; | |
| // Simulate finding more content while scrolling | |
| if (Math.random() > 0.3) { // 70% chance of finding more content | |
| setTimeout(() => { | |
| const newContacts = Math.floor(Math.random() * 3); | |
| const scrollResults = []; | |
| for (let i = 0; i < newContacts; i++) { | |
| const contact = { | |
| url: url + '?scroll=' + scrollCount, | |
| email: document.getElementById('extractEmails').checked ? generateRandomEmail() : null, | |
| phone: document.getElementById('extractPhones').checked ? generateRandomPhone() : null, | |
| profileUrl: 'https://example.com/profile/scroll_' + Math.random().toString(36).substring(7), | |
| timestamp: new Date().toISOString() | |
| }; | |
| if (contact.email || contact.phone) { | |
| foundContacts++; | |
| scrollResults.push(contact); | |
| results.push(contact); | |
| } | |
| } | |
| if (scrollResults.length > 0) { | |
| addResultsToUI(scrollResults); | |
| updateUI(); | |
| } | |
| }, 1000); | |
| } | |
| }, 2000); | |
| } | |
| // Add results to UI | |
| function addResultsToUI(newResults) { | |
| const resultsDiv = resultsContainer.querySelector('.divide-y') || document.createElement('div'); | |
| resultsDiv.className = 'divide-y divide-gray-200'; | |
| newResults.forEach(result => { | |
| const resultElement = document.createElement('div'); | |
| resultElement.className = 'p-4 hover:bg-gray-50 transition fade-in'; | |
| let html = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <h3 class="font-medium text-gray-800">${result.url}</h3> | |
| <div class="mt-2 flex flex-wrap gap-2"> | |
| `; | |
| if (result.email) { | |
| html += ` | |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800"> | |
| <i class="fas fa-envelope mr-1"></i> ${result.email} | |
| </span> | |
| `; | |
| } | |
| if (result.phone) { | |
| html += ` | |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"> | |
| <i class="fas fa-phone mr-1"></i> ${result.phone} | |
| </span> | |
| `; | |
| } | |
| const sendFriendRequests = document.getElementById('sendFriendRequests').checked; | |
| if (sendFriendRequests && result.profileUrl) { | |
| html += ` | |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800"> | |
| <i class="fas fa-user-plus mr-1"></i> Friend request sent | |
| </span> | |
| `; | |
| } | |
| html += ` | |
| </div> | |
| </div> | |
| <div class="text-xs text-gray-500">${new Date(result.timestamp).toLocaleTimeString()}</div> | |
| </div> | |
| `; | |
| resultElement.innerHTML = html; | |
| resultsDiv.prepend(resultElement); | |
| }); | |
| if (!resultsContainer.querySelector('.divide-y')) { | |
| resultsContainer.appendChild(resultsDiv); | |
| } | |
| // Scroll to top to show new results | |
| resultsContainer.scrollTop = 0; | |
| } | |
| // Update counters and UI | |
| function updateUI() { | |
| processedCount.textContent = processedPages; | |
| foundCount.textContent = foundContacts; | |
| } | |
| // Update memory usage (simulated) | |
| function updateMemoryUsage() { | |
| const usedMB = Math.floor(50 + Math.random() * 50); // Random between 50-100 MB | |
| memoryUsage.textContent = `Memory: ${usedMB} MB`; | |
| } | |
| // Get delay based on selected speed | |
| function getDelay() { | |
| const speed = document.getElementById('scrapingSpeed').value; | |
| switch (speed) { | |
| case 'slow': return 5000; | |
| case 'medium': return 2000; | |
| case 'fast': return 0; | |
| default: return 2000; | |
| } | |
| } | |
| // Show alert message | |
| function showAlert(message, type) { | |
| const alertDiv = document.createElement('div'); | |
| alertDiv.className = `fixed bottom-4 right-4 p-4 rounded-lg shadow-lg text-white max-w-md z-50 fade-in ${type === 'error' ? 'bg-red-500' : type === 'success' ? 'bg-green-500' : type === 'warning' ? 'bg-yellow-500' : 'bg-blue-500'}`; | |
| alertDiv.innerHTML = ` | |
| <div class="flex items-center"> | |
| <i class="fas ${type === 'error' ? 'fa-exclamation-circle' : type === 'success' ? 'fa-check-circle' : type === 'warning' ? 'fa-exclamation-triangle' : 'fa-info-circle'} mr-2"></i> | |
| <span>${message}</span> | |
| <button class="ml-4" onclick="this.parentElement.parentElement.remove()"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| `; | |
| document.body.appendChild(alertDiv); | |
| // Auto-remove after 5 seconds | |
| setTimeout(() => { | |
| if (alertDiv.parentNode) { | |
| alertDiv.classList.remove('fade-in'); | |
| alertDiv.classList.add('fade-out'); | |
| setTimeout(() => alertDiv.remove(), 300); | |
| } | |
| }, 5000); | |
| } | |
| // Helper functions for demo data | |
| function generateRandomEmail() { | |
| const domains = ['gmail.com', 'yahoo.com', 'outlook.com', 'protonmail.com', 'icloud.com']; | |
| const name = Math.random().toString(36).substring(2, 10); | |
| const domain = domains[Math.floor(Math.random() * domains.length)]; | |
| return `${name}@${domain}`; | |
| } | |
| function generateRandomPhone() { | |
| const prefixes = ['+1', '+44', '+49', '+33', '+81']; | |
| const prefix = prefixes[Math.floor(Math.random() * prefixes.length)]; | |
| let phone = prefix; | |
| for (let i = 0; i < 10; i++) { | |
| phone += Math.floor(Math.random() * 10); | |
| if (i === 2 || i === 5) phone += ' '; | |
| } | |
| return phone; | |
| } | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=misterxno1/scraper" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |