标签搜索
侧边栏壁纸
  • 累计撰写 45 篇文章
  • 累计收到 1 条评论

github_tools

Curry
2025-11-21 / 0 评论 / 0 阅读 / 正在检测是否收录...
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>IP延迟检测器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: Georgia, 'Times New Roman', serif;
            line-height: 1.6;
            color: #333;
            background-color: #fff;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .container {
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            padding: 40px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
            max-width: 800px;
            width: 100%;
        }

        h1 {
            text-align: center;
            color: #333;
            margin-bottom: 20px;
            font-size: 2em;
        }

        .author-link {
            text-align: center;
            margin-bottom: 25px;
        }

        .author-link a {
            color: #667eea;
            text-decoration: none;
            font-size: 0.9em;
            padding: 6px 12px;
            border: 1px solid #667eea;
            border-radius: 20px;
            transition: all 0.3s ease;
            display: inline-flex;
            align-items: center;
            gap: 5px;
        }

        .author-link a:hover {
            background: #667eea;
            color: white;
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
        }

        .ip-list {
            display: grid;
            gap: 15px;
            margin-bottom: 30px;
        }

        .ip-item {
            background: #f8f9fa;
            padding: 20px;
            border-radius: 12px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            transition: all 0.3s ease;
            border: 2px solid transparent;
        }

        .ip-item:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
        }

        .ip-item.fastest {
            background: #f0f8ff;
            border-color: #0000EE;
        }

        @keyframes glow {
            0%, 100% {
                box-shadow: 0 0 5px rgba(76, 175, 80, 0.5);
            }
            50% {
                box-shadow: 0 0 20px rgba(76, 175, 80, 0.8);
            }
        }

        .ip-address {
            font-weight: 600;
            color: #333;
            font-size: 1.1em;
            font-family: 'Courier New', monospace;
        }

        .latency {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .latency-value {
            font-weight: bold;
            font-size: 1.2em;
            min-width: 100px;
            text-align: right;
        }

        .latency-good {
            color: #006633;
        }

        .latency-medium {
            color: #FF9800;
        }

        .latency-bad {
            color: #f44336;
        }

        .latency-testing {
            color: #2196F3;
        }

        .latency-error {
            color: #9e9e9e;
        }

        .status {
            width: 12px;
            height: 12px;
            border-radius: 50%;
        }

        .status-good {
            background: #4CAF50;
            animation: pulse 2s infinite;
        }

        .status-medium {
            background: #FF9800;
            animation: pulse 2s infinite;
        }

        .status-bad {
            background: #f44336;
            animation: pulse 2s infinite;
        }

        .status-testing {
            background: #2196F3;
            animation: spin 1s linear infinite;
        }

        .status-error {
            background: #9e9e9e;
        }

        @keyframes pulse {
            0%, 100% {
                opacity: 1;
            }
            50% {
                opacity: 0.5;
            }
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        .best-ip-section {
            background: #f9f9f9;
            border: 1px solid #ddd;
            padding: 25px;
            border-radius: 12px;
            text-align: center;
        }

        .best-ip-label {
            color: #333;
            font-size: 1.1em;
            margin-bottom: 15px;
            font-weight: 500;
        }

        .best-ip-box {
            background: white;
            padding: 20px;
            border-radius: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
            transition: all 0.3s ease;
            min-width: 350px;
        }

        .best-ip-box.disabled {
            opacity: 0.6;
        }

        .best-ip-value {
            font-size: 1.2em;
            font-weight: bold;
            color: #11276e;
            font-family: 'Courier New', monospace;
            word-break: break-all;
            text-align: center;
        }

        .copy-icon {
            color: #11276e;
            font-size: 1.5em;
        }

        .copied-toast {
            position: fixed;
            top: 20px;
            right: 20px;
            background: #f0f0f0;
            color: #333;
            padding: 15px 25px;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
            display: none;
            animation: slideIn 0.3s ease;
            z-index: 1000;
        }

        .copied-toast.show {
            display: block;
        }

        @keyframes slideIn {
            from {
                transform: translateX(400px);
                opacity: 0;
            }
            to {
                transform: translateX(0);
                opacity: 1;
            }
        }

        .test-button {
            width: 100%;
            padding: 15px;
            background: #f0f0f0;
            color: #333;
            border: 2px solid #333;
            border-radius: 8px;
            font-size: 1.1em;
            font-weight: 600;
            cursor: pointer;
            margin-bottom: 20px;
            transition: all 0.3s ease;
        }

        .test-button:hover:not(:disabled) {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(17, 39, 110, 0.2);
        }

        .test-button:disabled {
            opacity: 0.6;
            cursor: not-allowed;
        }

        .loading-spinner {
            display: inline-block;
            width: 20px;
            height: 20px;
            border: 3px solid rgba(255, 255, 255, 0.3);
            border-radius: 50%;
            border-top-color: white;
            animation: spin 1s linear infinite;
            margin-right: 10px;
        }

        .info-text {
            text-align: center;
            color: #666;
            font-size: 0.9em;
            margin-top: 15px;
        }

        .update-info {
            text-align: center;
            color: #999;
            font-size: 0.85em;
            margin-bottom: 20px;
            padding: 8px;
            background: rgba(0, 0, 0, 0.05);
            border-radius: 6px;
        }

        .usage-guide {
            background: #f9f9f9;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
        }

        .usage-guide h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.1em;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .usage-steps {
            color: #555;
            font-size: 0.9em;
            line-height: 1.6;
        }

        .usage-steps ol {
            margin-left: 20px;
        }

        .usage-steps li {
            margin-bottom: 8px;
        }

        .usage-steps code {
            background: #f5f5f5;
            padding: 2px 6px;
            border-radius: 3px;
            font-family: 'Courier New', monospace;
            color: #333;
        }

        .copy-button {
            background: #f0f0f0;
            color: #333;
            border: 2px solid #333;
            padding: 12px 20px;
            border-radius: 6px;
            font-size: 1em;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            display: flex;
            align-items: center;
            gap: 8px;
            margin-left: 15px;
        }

        .copy-button:hover:not(:disabled) {
            background: #45a049;
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3);
        }

        .copy-button:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
        }

        .copy-hint {
            color: white;
            font-size: 0.85em;
            margin-top: 10px;
            font-style: italic;
        }

        .https-warning {
            background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
            border: none;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 20px;
            color: white;
            text-align: center;
        }

        .https-warning.error-mode {
            background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
        }

        .https-warning h3 {
            margin: 0 0 15px 0;
            font-size: 1.2em;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
        }

        .https-warning p {
            margin: 10px 0;
            line-height: 1.5;
            font-size: 0.95em;
        }

        .switch-to-http-btn {
            background: white;
            color: #ff6b6b;
            border: none;
            padding: 12px 24px;
            border-radius: 8px;
            font-size: 1em;
            font-weight: 600;
            cursor: pointer;
            margin-top: 10px;
            transition: all 0.3s ease;
            display: inline-flex;
            align-items: center;
            gap: 8px;
        }

        .switch-to-http-btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        }

        .limited-functionality {
            opacity: 0.6;
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🌐 IP延迟检测器</h1>

        <div class="author-link">
            <a href="https://xiangyu.cv" target="_blank" rel="noopener noreferrer">
                <span>✨</span>
                <span>访问我的个人主页</span>
                <span>→</span>
            </a>
        </div>

        <!-- HTTPS警告框 - 默认隐藏 -->
        <div class="https-warning" id="httpsWarning" style="display: none;">
            <h3>⚠️ 安全模式限制</h3>
            <p>当前您通过HTTPS安全协议访问本页面,由于浏览器安全策略,无法进行HTTP直连测试。</p>
            <p>为了获得最佳的IP延迟测试体验,建议切换到HTTP版本。</p>
            <button class="switch-to-http-btn" onclick="switchToHttpVersion()">
                <span>🚀</span>
                <span>切换到HTTP版本</span>
            </button>
        </div>

        <button class="test-button" id="testBtn" onclick="testLatency()">
            <span id="btnText">开始测试延迟</span>
        </button>

        <div class="update-info" id="updateInfo" style="display: none;">
            IP列表更新于 <span id="updateTime"></span>
        </div>

        <div class="ip-list" id="ipList"></div>
        

        <div class="best-ip-section">
            <div class="best-ip-label">✨ 最佳GitHub IP地址(延迟最低)</div>
            <div style="display: flex; align-items: center; justify-content: center;">
                <div class="best-ip-box" id="bestIpBox">
                    <div class="best-ip-value" id="bestIp">等待测试出最佳GitHub hosts条目...</div>
                </div>
                <button class="copy-button" onclick="copyToClipboard()" id="copyBtn" disabled>
                    <span>📋</span>
                    <span>复制hosts条目</span>
                </button>
            </div>
            <div class="copy-hint">复制内容格式:IP地址 github.com</div>
        </div>

        <div class="usage-guide">
            <h3>📖 使用说明</h3>
            <div class="usage-steps">
                <ol>
                    <li>点击上方"复制hosts条目"按钮,复制最快的GitHub IP</li>
                    <li>打开hosts文件:
                        <br><code>Windows: C:\Windows\System32\drivers\etc\hosts</code>
                        <br><code>Mac/Linux: /etc/hosts</code>
                    </li>
                    <li>将复制的内容粘贴到hosts文件末尾</li>
                    <li>保存文件即可享受更快的GitHub访问速度</li>
                </ol>
            </div>
        </div>
    </div>
    <div class="copied-toast" id="toast">✅ 已复制到剪贴板!</div>

    <script>
        // IP地址列表 - 从远程URL获取
        let ipAddresses = [];
        let latencyResults = {};
        let isTesting = false;
        let ipListLoaded = false;
        let ipListUpdateTime = null;

        // JSONP回调函数 - 支持两种名称
        function ipCallback(data) {
            handleJSONPResponse(data);
        }

        function callback(data) {
            handleJSONPResponse(data);
        }

        // 统一处理JSONP响应
        function handleJSONPResponse(data) {
            const btnText = document.getElementById('btnText');
            console.log('JSONP响应数据:', data);

            try {
                if (data.status === 'success' && data.ips && Array.isArray(data.ips)) {
                    // 过滤出有效的IP地址
                    ipAddresses = data.ips.filter(ip =>
                        typeof ip === 'string' && /^(\d{1,3}\.){3}\d{1,3}$/.test(ip.trim())
                    );

                    // 处理更新时间
                    if (data.updated) {
                        ipListUpdateTime = data.updated;
                        displayUpdateTime();
                    }

                    console.log(`成功获取 ${ipAddresses.length} 个IP地址,更新时间: ${data.updated}`);
                } else {
                    throw new Error('数据格式错误');
                }
            } catch (error) {
                console.error('JSONP数据解析失败:', error);
                useDefaultIPList();
            }

            ipListLoaded = true;
            // 立即显示所有IP为"测试中"状态
            displayAllIPs();
            btnText.textContent = '开始测试延迟';
        }

        // 显示更新时间
        function displayUpdateTime() {
            if (!ipListUpdateTime) return;

            const updateInfo = document.getElementById('updateInfo');
            const updateTimeElement = document.getElementById('updateTime');

            try {
                // 尝试解析ISO时间格式
                const date = new Date(ipListUpdateTime);
                if (!isNaN(date.getTime())) {
                    // 格式化为本地时间
                    updateTimeElement.textContent = date.toLocaleString('zh-CN', {
                        year: 'numeric',
                        month: '2-digit',
                        day: '2-digit',
                        hour: '2-digit',
                        minute: '2-digit',
                        second: '2-digit'
                    });
                    updateInfo.style.display = 'block';
                } else {
                    // 如果不是有效时间格式,直接显示原始字符串
                    updateTimeElement.textContent = ipListUpdateTime;
                    updateInfo.style.display = 'block';
                }
            } catch (error) {
                updateTimeElement.textContent = ipListUpdateTime;
                updateInfo.style.display = 'block';
            }
        }

        // 检测是否为本地文件协议
        function isLocalFile() {
            return window.location.protocol === 'file:';
        }

        // 使用默认IP列表
        function useDefaultIPList() {
            console.log('使用默认IP列表');
            ipAddresses = [
                '140.82.116.4',
                '140.82.121.3',
                '140.82.121.4',
                '20.205.243.166',
                '20.26.156.215',
                '20.27.177.113'
            ];

            // 隐藏更新时间信息
            document.getElementById('updateInfo').style.display = 'none';

            // 立即显示所有IP为"测试中"状态
            if (ipListLoaded) {
                displayAllIPs();
            }
        }

        // 使用JSONP获取IP列表
        function fetchIPList() {
            const btnText = document.getElementById('btnText');
            btnText.innerHTML = '<span class="loading-spinner"></span>获取IP列表...';

            // 先尝试不带参数的请求
            tryJSONPRequest('https://xiangyu.cv/github_hosts.txt');

            // 如果3秒内没有成功,再尝试带callback参数的请求
            setTimeout(() => {
                if (!ipListLoaded) {
                    console.log('尝试带callback参数的JSONP请求');
                    const timestamp = Date.now();
                    const random = Math.random().toString(36).substring(7);
                    tryJSONPRequest(`https://xiangyu.cv/github_hosts.txt?callback=callback&t=${timestamp}&r=${random}`);
                }
            }, 3000);

            // 总超时时间
            setTimeout(() => {
                if (!ipListLoaded) {
                    console.error('所有JSONP请求都超时,使用默认IP列表');
                    useDefaultIPList();
                    ipListLoaded = true;
                    displayAllIPs();
                    btnText.textContent = '开始测试延迟';
                }
            }, 10000);
        }

        // 尝试JSONP请求的通用函数
        function tryJSONPRequest(url) {
            // 清理之前的JSONP脚本
            const existingScript = document.getElementById('jsonp-script');
            if (existingScript) {
                existingScript.remove();
            }

            // 创建JSONP脚本
            const script = document.createElement('script');
            script.id = 'jsonp-script';
            script.src = url;

            console.log('发起JSONP请求:', url);

            script.onerror = function() {
                console.error('JSONP脚本加载失败:', url);
                // 不立即使用默认列表,让其他尝试继续
            };

            script.onload = function() {
                console.log('JSONP脚本加载完成:', url);
                // 如果3秒内还没有收到回调,可能回调函数名不匹配
                setTimeout(() => {
                    if (!ipListLoaded) {
                        console.warn('JSONP脚本已加载但未收到回调,可能是回调函数名不匹配');
                    }
                }, 3000);
            };

            document.head.appendChild(script);
        }

        // 显示所有IP(初始状态)- 保持原始顺序
        function displayAllIPs() {
            const ipList = document.getElementById('ipList');
            ipList.innerHTML = '';

            // 按原始顺序显示所有IP
            ipAddresses.forEach(ip => {
                const ipItem = document.createElement('div');
                ipItem.className = 'ip-item';
                ipItem.setAttribute('data-ip', ip);
                ipItem.innerHTML = `
                    <div class="ip-address">${ip}</div>
                    <div class="latency">
                        <div class="latency-value latency-testing">测试中...</div>
                        <div class="status status-testing"></div>
                    </div>
                `;
                ipList.appendChild(ipItem);
            });
        }

        // 测试单个IP的延迟 - 类似 nc -w5 -z -vv IP 80
        async function testSingleIP(ip) {
            const testCount = 3; // 测试3次取平均值
            let successfulTests = [];

            // 第一次测试时立即显示第一次结果
            let firstResultShown = false;

            for (let i = 0; i < testCount; i++) {
                try {
                    const startTime = performance.now();

                    // 使用Image对象来测试连接,避免CORS和HTTPS跳转问题
                    const testConnection = new Promise((resolve, reject) => {
                        const img = new Image();

                        // 任何响应(包括404、302等)都算连接成功
                        img.onload = () => resolve(true);
                        img.onerror = () => resolve(true); // 即使图片加载失败,说明服务器有响应

                        // 超时控制
                        const timeout = setTimeout(() => {
                            img.src = ''; // 停止加载
                            reject(new Error('timeout'));
                        }, 5000);

                        // 清理函数
                        const cleanup = () => clearTimeout(timeout);
                        img.onload = () => { cleanup(); resolve(true); };
                        img.onerror = () => { cleanup(); resolve(true); };

                        // 发起请求,添加随机参数避免缓存
                        img.src = `http://${ip}:80/?t=${Date.now()}&r=${Math.random()}`;
                    });

                    await testConnection;

                    const endTime = performance.now();
                    const latency = Math.round(endTime - startTime);

                    successfulTests.push(latency);

                    // 如果是第一次成功的测试,立即显示结果
                    if (!firstResultShown && successfulTests.length > 0) {
                        firstResultShown = true;
                        updateIPItem(ip, latency);
                        // 立即更新最佳IP(可能是最快的)
                        updateBestIP();
                    }

                } catch (error) {
                    // 超时或其他错误,不计入成功测试
                    console.log(`IP ${ip} 第${i + 1}次测试失败`);
                }

                // 每次测试间隔100ms
                if (i < testCount - 1) {
                    await new Promise(resolve => setTimeout(resolve, 100));
                }
            }

            // 所有测试完成后,返回最终结果
            if (successfulTests.length > 0) {
                const finalLatency = Math.round(successfulTests.reduce((a, b) => a + b) / successfulTests.length);
                return finalLatency;
            }

            return null; // 所有测试都失败(无法连接)
        }

        function getLatencyClass(latency) {
            if (latency === null) return 'error';
            if (latency < 100) return 'good';
            if (latency < 300) return 'medium';
            return 'bad';
        }

        function updateIPItem(ip, latency) {
            const existingItem = document.querySelector(`[data-ip="${ip}"]`);
            if (!existingItem) return;

            const latencyClass = getLatencyClass(latency);
            const latencyText = latency === null ? '超时' : latency === 'testing' ? '测试中...' : `${latency}ms`;

            // 只更新延迟显示,不重新创建元素,保持原始顺序
            const latencyElement = existingItem.querySelector('.latency');
            if (latencyElement) {
                latencyElement.innerHTML = `
                    <div class="latency-value latency-${latencyClass}">${latencyText}</div>
                    <div class="status status-${latencyClass}"></div>
                `;
            }
        }

        function updateBestIP() {
            // 找出所有已完成的测试结果
            const validResults = Object.entries(latencyResults).filter(([_, latency]) =>
                latency !== null && latency !== 'testing' && typeof latency === 'number'
            );

            if (validResults.length === 0) {
                return;
            }

            // 找出延迟最低的IP
            const sortedResults = validResults.sort((a, b) => a[1] - b[1]);
            const fastestIP = sortedResults[0][0];
            const fastestLatency = sortedResults[0][1];

            // 更新最佳IP显示,显示完整的hosts格式
            document.getElementById('bestIp').textContent = `${fastestIP} github.com`;
            document.getElementById('bestIpBox').classList.remove('disabled');
            document.getElementById('copyBtn').disabled = false;

            // 移除所有 fastest 样式
            document.querySelectorAll('.ip-item.fastest').forEach(item => {
                item.classList.remove('fastest');
            });

            // 给最快IP添加 fastest 样式
            const fastestItem = document.querySelector(`[data-ip="${fastestIP}"]`);
            if (fastestItem) {
                fastestItem.classList.add('fastest');
            }

            console.log(`当前最快IP: ${fastestIP} (${fastestLatency}ms)`);
        }

        async function testLatency() {
            if (isTesting || !ipListLoaded) return;

            isTesting = true;
            const testBtn = document.getElementById('testBtn');
            const btnText = document.getElementById('btnText');

            testBtn.disabled = true;
            btnText.innerHTML = '<span class="loading-spinner"></span>测试中...';

            latencyResults = {};
            document.getElementById('bestIp').textContent = '正在测试最佳GitHub hosts条目...';
            document.getElementById('bestIpBox').classList.add('disabled');
            document.getElementById('copyBtn').disabled = true;

            // 确保所有IP都显示在列表中
            displayAllIPs();

            // 设置所有IP为测试中状态
            ipAddresses.forEach(ip => {
                latencyResults[ip] = 'testing';
                updateIPItem(ip, 'testing');
            });

            // 并发测试所有IP
            const testPromises = ipAddresses.map(async ip => {
                const latency = await testSingleIP(ip);
                latencyResults[ip] = latency;
                // 更新最终结果
                updateIPItem(ip, latency);
                // 实时更新最佳IP
                updateBestIP();
            });

            await Promise.all(testPromises);

            // 所有测试完成后,最后更新一次最佳IP
            updateBestIP();

            testBtn.disabled = false;
            btnText.textContent = '重新测试延迟';
            isTesting = false;
        }

        function copyToClipboard() {
            const bestIpContent = document.getElementById('bestIp').textContent;

            if (bestIpContent.includes('等待测试') || bestIpContent.includes('正在测试') || bestIpContent === '无可用IP') {
                return;
            }

            // 直接复制显示的内容(已经是hosts格式)
            const contentToCopy = bestIpContent;

            // 使用现代的 Clipboard API
            if (navigator.clipboard && navigator.clipboard.writeText) {
                navigator.clipboard.writeText(contentToCopy).then(function() {
                    showSuccessMessage();
                }).catch(function(err) {
                    // 如果 Clipboard API 失败,使用传统方法
                    fallbackCopy(contentToCopy);
                });
            } else {
                // 浏览器不支持 Clipboard API,使用传统方法
                fallbackCopy(contentToCopy);
            }
        }

        function fallbackCopy(text) {
            const textArea = document.createElement('textarea');
            textArea.value = text;
            textArea.style.position = 'fixed';
            textArea.style.left = '-9999px';
            document.body.appendChild(textArea);
            textArea.select();

            try {
                document.execCommand('copy');
                showSuccessMessage();
            } catch (err) {
                alert('复制失败,请手动复制以下内容:\n' + text);
            }

            document.body.removeChild(textArea);
        }

        function showSuccessMessage() {
            const toast = document.getElementById('toast');
            toast.textContent = '✅ 已复制hosts条目到剪贴板!';
            toast.classList.add('show');

            // 3秒后隐藏成功消息
            setTimeout(() => {
                toast.classList.remove('show');
                toast.textContent = '✅ 已复制到剪贴板!'; // 恢复原始文本
            }, 3000);
        }

        // 检测当前协议并显示相应提示
        function detectProtocolAndShowWarning() {
            const isHttps = window.location.protocol === 'https:';
            const isLocal = isLocalFile();
            const httpsWarning = document.getElementById('httpsWarning');
            const testBtn = document.getElementById('testBtn');
            const ipList = document.getElementById('ipList');
            const bestIpSection = document.querySelector('.best-ip-section');
            const usageGuide = document.querySelector('.usage-guide');

            if (isHttps) {
                // HTTPS模式:显示无法工作的提示
                httpsWarning.style.display = 'block';
                httpsWarning.classList.add('error-mode');
                httpsWarning.querySelector('h3').innerHTML = '❌ 无法正常工作';
                httpsWarning.querySelector('p:nth-child(2)').textContent = '当前您通过HTTPS安全协议访问本页面,由于浏览器安全策略阻止HTTP请求,IP延迟测试功能无法正常工作。';
                httpsWarning.querySelector('p:nth-child(3)').textContent = '请使用HTTP协议访问本页面,或下载到本地HTML文件使用。';

                // 修改按钮为禁用状态
                const switchBtn = httpsWarning.querySelector('.switch-to-http-btn');
                if (switchBtn) {
                    switchBtn.innerHTML = '<span>🚫</span><span>HTTPS模式不支持</span>';
                    switchBtn.disabled = true;
                    switchBtn.style.opacity = '0.5';
                    switchBtn.style.cursor = 'not-allowed';
                }

                testBtn.classList.add('limited-functionality');
                testBtn.disabled = true;
                document.getElementById('btnText').textContent = '无法测试';

                if (ipList) ipList.classList.add('limited-functionality');
                if (bestIpSection) bestIpSection.classList.add('limited-functionality');
                if (usageGuide) usageGuide.classList.add('limited-functionality');

                console.log('检测到HTTPS访问,显示无法工作提示');
            } else if (isLocal) {
                // 本地文件模式:显示本地提示,但启用功能
                httpsWarning.style.display = 'block';
                httpsWarning.querySelector('h3').innerHTML = '🏠 本地文件模式';
                httpsWarning.querySelector('p:nth-child(2)').textContent = '当前您正在本地打开本页面,某些功能可能受限。建议部署到Web服务器或使用本地HTTP服务器。';
                httpsWarning.querySelector('p:nth-child(3)').textContent = 'IP测试功能可以正常使用,但无法获取远程IP列表更新。';

                // 隐藏切换按钮,改为提示信息
                const switchBtn = httpsWarning.querySelector('.switch-to-http-btn');
                if (switchBtn) {
                    switchBtn.style.display = 'none';
                }

                // 启用测试功能
                testBtn.classList.remove('limited-functionality');
                testBtn.disabled = false;
                document.getElementById('btnText').textContent = '开始测试延迟';

                if (ipList) ipList.classList.remove('limited-functionality');
                if (bestIpSection) bestIpSection.classList.remove('limited-functionality');
                if (usageGuide) usageGuide.classList.remove('limited-functionality');

                console.log('检测到本地文件访问,启用本地模式');
            } else {
                // HTTP模式:正常功能
                httpsWarning.style.display = 'none';
                testBtn.classList.remove('limited-functionality');
                testBtn.disabled = false;
                document.getElementById('btnText').textContent = '开始测试延迟';

                if (ipList) ipList.classList.remove('limited-functionality');
                if (bestIpSection) bestIpSection.classList.remove('limited-functionality');
                if (usageGuide) usageGuide.classList.remove('limited-functionality');

                console.log('检测到HTTP访问,启用完整功能');
            }
        }

        // 切换到HTTP版本
        function switchToHttpVersion() {
            const currentUrl = window.location.href;
            const httpUrl = currentUrl.replace('https://', 'http://');

            // 在当前窗口打开HTTP版本
            window.open(httpUrl, '_self');
        }

        // 页面加载时先检测协议,然后获取IP列表,最后开始测试
        window.onload = async () => {
            // 检测协议并显示相应提示
            detectProtocolAndShowWarning();

            const isLocal = isLocalFile();
            const isHttp = window.location.protocol === 'http:';

            // HTTP模式或本地模式:执行测试流程
            if (isHttp || isLocal) {
                if (isLocal) {
                    // 本地模式:直接使用默认IP列表,跳过JSONP请求
                    console.log('本地文件模式:跳过JSONP请求,直接使用默认IP列表');
                    ipListLoaded = true;
                    useDefaultIPList();
                    setTimeout(() => {
                        testLatency();
                    }, 500);
                } else {
                    // HTTP模式:正常获取IP列表
                    await fetchIPList();
                    setTimeout(() => {
                        testLatency();
                    }, 500);
                }
            }
        };
    </script>
</body>
</html>

0

评论 (0)

取消