"https://api.proxyscrape.com/v2/?request=getproxies&protocol=http&timeout=10000&country=all", "https://api.proxyscrape.com/v2/?request=getproxies&protocol=https&timeout=10000&country=all", "https://api.proxyscrape.com/v2/?request=getproxies&protocol=socks4&timeout=10000&country=all", "https://api.proxyscrape.com/v2/?request=getproxies&protocol=socks5&timeout=10000&country=all", "https://www.proxy-list.download/api/v1/get?type=http", "https://www.proxy-list.download/api/v1/get?type=https", "https://www.proxy-list.download/api/v1/get?type=socks4", "https://www.proxy-list.download/api/v1/get?type=socks5", "https://openproxy.space/list/http", "https://openproxy.space/list/socks4", "https://openproxy.space/list/socks5", "https://proxylist.geonode.com/api/proxy-list?limit=500&page=1&sort_by=lastChecked&sort_type=desc", "https://raw.githubusercontent.com/almroot/proxylist/master/list.txt", "https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/http_proxies.txt", "https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/socks4_proxies.txt", "https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/socks5_proxies.txt", "https://www.us-proxy.org/", "https://free-proxy-list.net/", "https://www.sslproxies.org/", "https://www.socks-proxy.net/", "https://www.proxy-list.download/api/v1/get?type=elite", "https://raw.githubusercontent.com/clarketm/proxy-list/master/proxy-list-raw.txt", "https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt", "https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks4.txt", "https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks5.txt", "https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/http.txt", "https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/socks4.txt", "https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/socks5.txt", "https://www.proxy-list.download/api/v1/get?type=transparent", "https://proxyspider.com/api/proxies.json?limit=1000", "https://proxy-daily.com/api/proxy?limit=100", "https://raw.githubusercontent.com/mertguvencli/http-proxy-list/main/proxy-list/data.txt", "https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-http.txt", "https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks4.txt", "https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks5.txt", "https://www.proxyscan.io/download?type=http", "https://www.proxyscan.io/download?type=socks4", "https://www.proxyscan.io/download?type=socks5", "https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt", "https://www.freeproxychecker.com/result/http_proxies.txt", "https://www.freeproxychecker.com/result/socks4_proxies.txt" ] # Endpoints for proxy testing TEST_URLS = [ "http://httpbin.org/ip", "http://api.ipify.org/", "http://icanhazip.com/", ] it should really be working - Follow Up Deployment
27a58da
verified
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>ProxyScraper Pro - Free Proxy Fetcher</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> | |
.gradient-bg { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
} | |
.proxy-card { | |
transition: all 0.3s ease; | |
} | |
.proxy-card:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 10px 20px rgba(0,0,0,0.1); | |
} | |
.progress-bar { | |
height: 5px; | |
background-color: #e0e0e0; | |
border-radius: 2px; | |
overflow: hidden; | |
} | |
.progress-fill { | |
height: 100%; | |
background: linear-gradient(90deg, #4facfe 0%, #00f2fe 100%); | |
transition: width 0.3s ease; | |
} | |
#proxyList { | |
max-height: 400px; | |
overflow-y: auto; | |
} | |
/* Custom scrollbar */ | |
#proxyList::-webkit-scrollbar { | |
width: 6px; | |
} | |
#proxyList::-webkit-scrollbar-track { | |
background: #f1f1f1; | |
} | |
#proxyList::-webkit-scrollbar-thumb { | |
background: #888; | |
border-radius: 3px; | |
} | |
#proxyList::-webkit-scrollbar-thumb:hover { | |
background: #555; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-100"> | |
<header class="gradient-bg text-white shadow-lg"> | |
<div class="container mx-auto px-4 py-6"> | |
<div class="flex flex-col md:flex-row justify-between items-center"> | |
<div class="flex items-center mb-4 md:mb-0"> | |
<i class="fas fa-shield-alt text-3xl mr-3"></i> | |
<h1 class="text-2xl md:text-3xl font-bold">ProxyScraper Pro</h1> | |
</div> | |
<div class="flex items-center space-x-4"> | |
<div class="hidden md:flex items-center space-x-2"> | |
<i class="fas fa-sync-alt"></i> | |
<span>Auto-update every <span id="updateInterval">30</span> min</span> | |
</div> | |
<button id="settingsBtn" class="p-2 rounded-full hover:bg-white hover:bg-opacity-20 transition"> | |
<i class="fas fa-cog"></i> | |
</button> | |
</div> | |
</div> | |
</div> | |
</header> | |
<main class="container mx-auto px-4 py-8"> | |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<!-- Control Panel --> | |
<div class="lg:col-span-1"> | |
<div class="bg-white rounded-lg shadow-md p-6 sticky top-6"> | |
<h2 class="text-xl font-semibold mb-4 flex items-center"> | |
<i class="fas fa-sliders-h mr-2 text-blue-500"></i> Control Panel | |
</h2> | |
<div class="mb-6"> | |
<label class="block text-gray-700 mb-2">Proxy Sources</label> | |
<div class="flex items-center mb-2"> | |
<input type="checkbox" id="githubCheck" class="mr-2" checked> | |
<label for="githubCheck">GitHub Repositories</label> | |
</div> | |
<div class="flex items-center mb-2"> | |
<input type="checkbox" id="customCheck" class="mr-2"> | |
<label for="customCheck">Custom URLs</label> | |
</div> | |
<div id="customUrlsContainer" class="hidden mt-2"> | |
<textarea id="customUrls" class="w-full p-2 border rounded" rows="3" placeholder="Enter custom proxy URLs (one per line)"></textarea> | |
</div> | |
</div> | |
<div class="mb-6"> | |
<label class="block text-gray-700 mb-2">Proxy Types</label> | |
<div class="grid grid-cols-2 gap-2"> | |
<div class="flex items-center"> | |
<input type="checkbox" id="httpCheck" class="mr-2" checked> | |
<label for="httpCheck">HTTP</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="httpsCheck" class="mr-2" checked> | |
<label for="httpsCheck">HTTPS</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="socks4Check" class="mr-2" checked> | |
<label for="socks4Check">SOCKS4</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="socks5Check" class="mr-2" checked> | |
<label for="socks5Check">SOCKS5</label> | |
</div> | |
</div> | |
</div> | |
<div class="mb-6"> | |
<label for="timeout" class="block text-gray-700 mb-2">Timeout (seconds)</label> | |
<input type="number" id="timeout" min="1" max="30" value="5" class="w-full p-2 border rounded"> | |
</div> | |
<div class="mb-6"> | |
<label for="limit" class="block text-gray-700 mb-2">Proxy Limit</label> | |
<input type="number" id="limit" min="1" max="10000" value="500" class="w-full p-2 border rounded"> | |
</div> | |
<button id="fetchBtn" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-3 px-4 rounded-lg font-medium transition flex items-center justify-center"> | |
<i class="fas fa-bolt mr-2"></i> Fetch Proxies | |
</button> | |
<div id="progressContainer" class="mt-4 hidden"> | |
<div class="flex justify-between text-sm text-gray-600 mb-1"> | |
<span>Progress</span> | |
<span id="progressText">0%</span> | |
</div> | |
<div class="progress-bar"> | |
<div id="progressFill" class="progress-fill" style="width: 0%"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Results Section --> | |
<div class="lg:col-span-2"> | |
<div class="bg-white rounded-lg shadow-md p-6 mb-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h2 class="text-xl font-semibold flex items-center"> | |
<i class="fas fa-list-ul mr-2 text-green-500"></i> Results | |
</h2> | |
<div class="flex space-x-2"> | |
<button id="exportBtn" class="bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-lg text-sm transition flex items-center disabled:opacity-50" disabled> | |
<i class="fas fa-file-export mr-1"></i> Export | |
</button> | |
<button id="copyBtn" class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-lg text-sm transition flex items-center disabled:opacity-50" disabled> | |
<i class="fas fa-copy mr-1"></i> Copy | |
</button> | |
<button id="clearBtn" class="bg-gray-500 hover:bg-gray-600 text-white py-2 px-4 rounded-lg text-sm transition flex items-center"> | |
<i class="fas fa-trash-alt mr-1"></i> Clear | |
</button> | |
</div> | |
</div> | |
<div class="flex justify-between items-center mb-4"> | |
<div class="flex space-x-4"> | |
<div class="text-center"> | |
<div class="text-2xl font-bold text-blue-500" id="totalProxies">0</div> | |
<div class="text-xs text-gray-500">Total</div> | |
</div> | |
<div class="text-center"> | |
<div class="text-2xl font-bold text-green-500" id="workingProxies">0</div> | |
<div class="text-xs text-gray-500">Working</div> | |
</div> | |
<div class="text-center"> | |
<div class="text-2xl font-bold text-red-500" id="failedProxies">0</div> | |
<div class="text-xs text-gray-500">Failed</div> | |
</div> | |
</div> | |
<div class="text-sm text-gray-500"> | |
Last updated: <span id="lastUpdated">Never</span> | |
</div> | |
</div> | |
<div class="border rounded-lg overflow-hidden"> | |
<div id="proxyList" class="divide-y divide-gray-200"> | |
<div class="p-4 text-center text-gray-500"> | |
No proxies fetched yet. Click "Fetch Proxies" to start. | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Stats Section --> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div class="bg-white rounded-lg shadow-md p-6"> | |
<h2 class="text-xl font-semibold mb-4 flex items-center"> | |
<i class="fas fa-chart-pie mr-2 text-purple-500"></i> Proxy Types | |
</h2> | |
<div id="typeChart" class="h-48 flex items-center justify-center"> | |
<div class="text-gray-400">No data available</div> | |
</div> | |
</div> | |
<div class="bg-white rounded-lg shadow-md p-6"> | |
<h2 class="text-xl font-semibold mb-4 flex items-center"> | |
<i class="fas fa-globe mr-2 text-orange-500"></i> Countries | |
</h2> | |
<div id="countryChart" class="h-48 flex items-center justify-center"> | |
<div class="text-gray-400">No data available</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</main> | |
<!-- Settings Modal --> | |
<div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden"> | |
<div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-md"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-xl font-semibold">Settings</h3> | |
<button id="closeSettings" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<div class="mb-4"> | |
<label for="autoUpdate" class="block text-gray-700 mb-2">Auto-update Interval (minutes)</label> | |
<input type="number" id="autoUpdate" min="5" max="240" value="30" class="w-full p-2 border rounded"> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-gray-700 mb-2">Notification</label> | |
<div class="flex items-center"> | |
<input type="checkbox" id="enableNotifications" class="mr-2"> | |
<label for="enableNotifications">Enable desktop notifications</label> | |
</div> | |
</div> | |
<div class="mb-4"> | |
<label class="block text-gray-700 mb-2">Dark Mode</label> | |
<div class="flex items-center"> | |
<input type="checkbox" id="darkMode" class="mr-2"> | |
<label for="darkMode">Enable dark mode</label> | |
</div> | |
</div> | |
<div class="flex justify-end space-x-3 mt-6"> | |
<button id="cancelSettings" class="px-4 py-2 border rounded-lg text-gray-700 hover:bg-gray-100 transition"> | |
Cancel | |
</button> | |
<button id="saveSettings" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition"> | |
Save | |
</button> | |
</div> | |
</div> | |
</div> | |
<footer class="bg-gray-800 text-white py-6 mt-12"> | |
<div class="container mx-auto px-4"> | |
<div class="flex flex-col md:flex-row justify-between items-center"> | |
<div class="mb-4 md:mb-0"> | |
<p>© 2023 ProxyScraper Pro. All rights reserved.</p> | |
</div> | |
<div class="flex space-x-4"> | |
<a href="#" class="hover:text-blue-300 transition">Privacy Policy</a> | |
<a href="#" class="hover:text-blue-300 transition">Terms of Service</a> | |
<a href="#" class="hover:text-blue-300 transition">GitHub</a> | |
</div> | |
</div> | |
</div> | |
</footer> | |
<script> | |
// DOM Elements | |
const fetchBtn = document.getElementById('fetchBtn'); | |
const exportBtn = document.getElementById('exportBtn'); | |
const copyBtn = document.getElementById('copyBtn'); | |
const clearBtn = document.getElementById('clearBtn'); | |
const settingsBtn = document.getElementById('settingsBtn'); | |
const closeSettings = document.getElementById('closeSettings'); | |
const cancelSettings = document.getElementById('cancelSettings'); | |
const saveSettings = document.getElementById('saveSettings'); | |
const settingsModal = document.getElementById('settingsModal'); | |
const customCheck = document.getElementById('customCheck'); | |
const customUrlsContainer = document.getElementById('customUrlsContainer'); | |
const proxyList = document.getElementById('proxyList'); | |
const progressContainer = document.getElementById('progressContainer'); | |
const progressFill = document.getElementById('progressFill'); | |
const progressText = document.getElementById('progressText'); | |
const totalProxies = document.getElementById('totalProxies'); | |
const workingProxies = document.getElementById('workingProxies'); | |
const failedProxies = document.getElementById('failedProxies'); | |
const lastUpdated = document.getElementById('lastUpdated'); | |
const updateInterval = document.getElementById('updateInterval'); | |
// State | |
let proxies = []; | |
let workingProxyCount = 0; | |
let failedProxyCount = 0; | |
let autoUpdateTimer = null; | |
// Event Listeners | |
fetchBtn.addEventListener('click', fetchProxies); | |
exportBtn.addEventListener('click', exportProxies); | |
copyBtn.addEventListener('click', copyProxies); | |
clearBtn.addEventListener('click', clearProxies); | |
settingsBtn.addEventListener('click', () => settingsModal.classList.remove('hidden')); | |
closeSettings.addEventListener('click', () => settingsModal.classList.add('hidden')); | |
cancelSettings.addEventListener('click', () => settingsModal.classList.add('hidden')); | |
saveSettings.addEventListener('click', saveSettingsHandler); | |
customCheck.addEventListener('change', toggleCustomUrls); | |
// Functions | |
function toggleCustomUrls() { | |
customUrlsContainer.classList.toggle('hidden', !customCheck.checked); | |
} | |
// Proxy endpoints | |
const PROXY_ENDPOINTS = [ | |
"https://api.proxyscrape.com/v2/?request=getproxies&protocol=http&timeout=10000&country=all", | |
"https://api.proxyscrape.com/v2/?request=getproxies&protocol=https&timeout=10000&country=all", | |
"https://api.proxyscrape.com/v2/?request=getproxies&protocol=socks4&timeout=10000&country=all", | |
"https://api.proxyscrape.com/v2/?request=getproxies&protocol=socks5&timeout=10000&country=all", | |
"https://www.proxy-list.download/api/v1/get?type=http", | |
"https://www.proxy-list.download/api/v1/get?type=https", | |
"https://www.proxy-list.download/api/v1/get?type=socks4", | |
"https://www.proxy-list.download/api/v1/get?type=socks5", | |
"https://openproxy.space/list/http", | |
"https://openproxy.space/list/socks4", | |
"https://openproxy.space/list/socks5", | |
"https://proxylist.geonode.com/api/proxy-list?limit=500&page=1&sort_by=lastChecked&sort_type=desc", | |
"https://raw.githubusercontent.com/almroot/proxylist/master/list.txt", | |
"https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/http_proxies.txt", | |
"https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/socks4_proxies.txt", | |
"https://raw.githubusercontent.com/Anonym0usWork1221/Free-Proxies/main/proxy_files/socks5_proxies.txt", | |
"https://raw.githubusercontent.com/clarketm/proxy-list/master/proxy-list-raw.txt", | |
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt", | |
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks4.txt", | |
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/socks5.txt", | |
"https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/http.txt", | |
"https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/socks4.txt", | |
"https://raw.githubusercontent.com/ShiftyTR/Proxy-List/master/socks5.txt", | |
"https://raw.githubusercontent.com/mertguvencli/http-proxy-list/main/proxy-list/data.txt", | |
"https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-http.txt", | |
"https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks4.txt", | |
"https://raw.githubusercontent.com/jetkai/proxy-list/main/online-proxies/txt/proxies-socks5.txt", | |
"https://raw.githubusercontent.com/hookzof/socks5_list/master/proxy.txt" | |
]; | |
// Test URLs for validation | |
const TEST_URLS = [ | |
"http://httpbin.org/ip", | |
"http://api.ipify.org/", | |
"http://icanhazip.com/" | |
]; | |
async function fetchProxies() { | |
// Reset state | |
proxies = []; | |
workingProxyCount = 0; | |
failedProxyCount = 0; | |
updateCounters(); | |
// Show loading state | |
fetchBtn.disabled = true; | |
fetchBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Fetching...'; | |
progressContainer.classList.remove('hidden'); | |
const proxyTypes = []; | |
if (document.getElementById('httpCheck').checked) proxyTypes.push('http'); | |
if (document.getElementById('httpsCheck').checked) proxyTypes.push('https'); | |
if (document.getElementById('socks4Check').checked) proxyTypes.push('socks4'); | |
if (document.getElementById('socks5Check').checked) proxyTypes.push('socks5'); | |
const limit = parseInt(document.getElementById('limit').value); | |
const timeout = parseInt(document.getElementById('timeout').value); | |
try { | |
// Fetch from all endpoints in parallel | |
const responses = await Promise.allSettled( | |
PROXY_ENDPOINTS.map(url => fetch(url).then(res => res.text())) | |
); | |
// Process responses | |
let rawProxies = []; | |
responses.forEach(response => { | |
if (response.status === 'fulfilled') { | |
const proxiesFromEndpoint = response.value | |
.split('\n') | |
.map(p => p.trim()) | |
.filter(p => p && p.includes(':')); | |
rawProxies = [...rawProxies, ...proxiesFromEndpoint]; | |
} | |
}); | |
// Deduplicate | |
const uniqueProxies = [...new Set(rawProxies)]; | |
// Shuffle and limit | |
const shuffledProxies = uniqueProxies | |
.sort(() => 0.5 - Math.random()) | |
.slice(0, limit); | |
// Validate proxies | |
await validateProxies(shuffledProxies, timeout); | |
} catch (error) { | |
console.error('Error fetching proxies:', error); | |
alert('Error fetching proxies. Check console for details.'); | |
} finally { | |
fetchBtn.disabled = false; | |
fetchBtn.innerHTML = '<i class="fas fa-bolt mr-2"></i> Fetch Proxies'; | |
exportBtn.disabled = workingProxyCount === 0; | |
copyBtn.disabled = workingProxyCount === 0; | |
lastUpdated.textContent = new Date().toLocaleString(); | |
if (!autoUpdateTimer) { | |
startAutoUpdate(); | |
} | |
} | |
} | |
async function validateProxies(proxyList, timeout) { | |
const batchSize = 20; | |
const testUrl = TEST_URLS[Math.floor(Math.random() * TEST_URLS.length)]; | |
for (let i = 0; i < proxyList.length; i += batchSize) { | |
const batch = proxyList.slice(i, i + batchSize); | |
const batchPromises = batch.map(proxy => testProxy(proxy, testUrl, timeout)); | |
const results = await Promise.allSettled(batchPromises); | |
results.forEach((result, index) => { | |
const proxy = batch[index]; | |
if (result.status === 'fulfilled' && result.value) { | |
proxies.push({ | |
proxy, | |
type: result.value.type || 'unknown', | |
country: result.value.country || 'unknown', | |
isWorking: true, | |
latency: result.value.latency | |
}); | |
workingProxyCount++; | |
} else { | |
proxies.push({ | |
proxy, | |
type: 'unknown', | |
country: 'unknown', | |
isWorking: false, | |
latency: null | |
}); | |
failedProxyCount++; | |
} | |
}); | |
updateCounters(); | |
displayProxies(); | |
updateProgress((i / proxyList.length) * 100); | |
} | |
updateProgress(100); | |
} | |
async function testProxy(proxy, testUrl, timeout) { | |
const controller = new AbortController(); | |
const timeoutId = setTimeout(() => controller.abort(), timeout * 1000); | |
try { | |
const startTime = Date.now(); | |
const response = await fetch(testUrl, { | |
signal: controller.signal, | |
headers: { 'Accept': 'application/json' } | |
}); | |
if (!response.ok) throw new Error('Invalid response'); | |
const latency = Date.now() - startTime; | |
const data = await response.json(); | |
return { | |
type: 'http', // Simplified for demo - would detect actual type | |
country: 'unknown', // Could implement geo lookup | |
latency | |
}; | |
} catch (error) { | |
throw error; | |
} finally { | |
clearTimeout(timeoutId); | |
} | |
} | |
function updateProgress(percent) { | |
progressFill.style.width = `${percent}%`; | |
progressText.textContent = `${Math.round(percent)}%`; | |
} | |
function updateCounters() { | |
totalProxies.textContent = proxies.length; | |
workingProxies.textContent = workingProxyCount; | |
failedProxies.textContent = failedProxyCount; | |
} | |
function displayProxies() { | |
if (proxies.length === 0) { | |
proxyList.innerHTML = '<div class="p-4 text-center text-gray-500">No proxies fetched yet. Click "Fetch Proxies" to start.</div>'; | |
return; | |
} | |
proxyList.innerHTML = ''; | |
// Sort by working first, then by latency | |
const sortedProxies = [...proxies].sort((a, b) => { | |
if (a.isWorking !== b.isWorking) return b.isWorking - a.isWorking; | |
if (a.isWorking && b.isWorking) return (a.latency || 0) - (b.latency || 0); | |
return 0; | |
}); | |
sortedProxies.forEach(proxy => { | |
const proxyElement = document.createElement('div'); | |
proxyElement.className = 'p-3 flex items-center justify-between proxy-card'; | |
const statusClass = proxy.isWorking ? 'bg-green-500' : 'bg-red-500'; | |
const statusText = proxy.isWorking ? 'Working' : 'Failed'; | |
proxyElement.innerHTML = ` | |
<div class="flex items-center space-x-3"> | |
<div class="w-3 h-3 rounded-full ${statusClass}"></div> | |
<div class="font-mono">${proxy.proxy}</div> | |
<span class="px-2 py-1 text-xs rounded-full bg-gray-100">${proxy.type}</span> | |
<span class="px-2 py-1 text-xs rounded-full bg-gray-100">${proxy.country}</span> | |
</div> | |
<div class="text-sm text-gray-500"> | |
${proxy.isWorking ? `${proxy.latency}ms` : statusText} | |
</div> | |
`; | |
proxyList.appendChild(proxyElement); | |
}); | |
} | |
function exportProxies() { | |
if (proxies.length === 0) return; | |
const workingProxies = proxies.filter(p => p.isWorking).map(p => p.proxy); | |
if (workingProxies.length === 0) { | |
alert('No working proxies to export!'); | |
return; | |
} | |
const blob = new Blob([workingProxies.join('\n')], { type: 'text/plain' }); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = `proxies_${new Date().toISOString().slice(0, 10)}.txt`; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
URL.revokeObjectURL(url); | |
} | |
function copyProxies() { | |
if (proxies.length === 0) return; | |
const workingProxies = proxies.filter(p => p.isWorking).map(p => p.proxy); | |
if (workingProxies.length === 0) { | |
alert('No working proxies to copy!'); | |
return; | |
} | |
navigator.clipboard.writeText(workingProxies.join('\n')) | |
.then(() => { | |
const originalText = copyBtn.innerHTML; | |
copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i> Copied!'; | |
setTimeout(() => { | |
copyBtn.innerHTML = originalText; | |
}, 2000); | |
}) | |
.catch(err => { | |
console.error('Failed to copy: ', err); | |
}); | |
} | |
function clearProxies() { | |
proxies = []; | |
workingProxyCount = 0; | |
failedProxyCount = 0; | |
updateCounters(); | |
proxyList.innerHTML = '<div class="p-4 text-center text-gray-500">No proxies fetched yet. Click "Fetch Proxies" to start.</div>'; | |
exportBtn.disabled = true; | |
copyBtn.disabled = true; | |
lastUpdated.textContent = 'Never'; | |
// Clear auto-update timer | |
if (autoUpdateTimer) { | |
clearInterval(autoUpdateTimer); | |
autoUpdateTimer = null; | |
} | |
} | |
function saveSettingsHandler() { | |
const interval = parseInt(document.getElementById('autoUpdate').value); | |
updateInterval.textContent = interval; | |
// Restart auto-update with new interval | |
if (autoUpdateTimer) { | |
clearInterval(autoUpdateTimer); | |
startAutoUpdate(); | |
} | |
// In a real app, you would save other settings to localStorage | |
settingsModal.classList.add('hidden'); | |
} | |
function startAutoUpdate() { | |
const interval = parseInt(document.getElementById('autoUpdate').value) * 60 * 1000; | |
autoUpdateTimer = setInterval(fetchProxies, interval); | |
} | |
// Initialize | |
toggleCustomUrls(); | |
</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=Kucjt/ppok" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |