您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为 Via 浏览器错误页面(404 Not Found 和网络连接失败)注入美化,404 页面采用幻境风格,网络连接失败页面采用生命美学与科幻风格,支持日夜模式自动切换
// ==UserScript== // @name Via 浏览器 404 和网络连接失败页面美化 // @namespace https://viayoo.com/ // @version 1.11 // @description 为 Via 浏览器错误页面(404 Not Found 和网络连接失败)注入美化,404 页面采用幻境风格,网络连接失败页面采用生命美学与科幻风格,支持日夜模式自动切换 // @author 是小白呀 & Grok // @match *://*/* // @license MIT // @grant none // ==/UserScript== (function() { 'use strict'; // 提取错误页面中的 URL(用于网络连接失败页面) function extractErrorUrl() { const bodyText = document.body ? document.body.innerText : ''; const urlMatch = bodyText.match(/(https?:\/\/[^\s]+)/i); return urlMatch ? urlMatch[0] : '未知地址'; } // 提取错误代码和服务器信息(用于 404 页面) function extractErrorInfo() { const bodyText = document.body ? document.body.innerText : ''; const errorCodeMatch = bodyText.match(/net::ERR_[A-Z_]+/) || document.title.match(/404 Not Found/) || ['404 Not Found']; const serverMatch = bodyText.match(/nginx/i) ? 'nginx' : ''; return { errorCode: errorCodeMatch[0], server: serverMatch }; } // 检查是否为 404 错误页面(严格匹配“404 Not Found”和“nginx”) function checkFor404Page() { let has404 = false; let hasNginx = false; // 检查标题 if (/404 Not Found/i.test(document.title)) { has404 = true; } // 检查 body 内容 if (document.body) { const text = document.body.innerText || ''; if (/404 Not Found/i.test(text)) { has404 = true; } if (/nginx/i.test(text)) { hasNginx = true; } } // 必须同时满足“404 Not Found”和“nginx” return has404 && hasNginx; } // 检查是否为网络连接失败页面 function checkForConnectionErrorPage() { // 排除 404 页面 if (checkFor404Page()) { return false; } // 快速检查标题 if (/无法打开|Error/i.test(document.title)) { return true; } // 检查 body 内容 if (document.body) { const text = document.body.innerText || ''; if (/net::ERR_|网页无法打开|无法连接|ERR_NAME_NOT_RESOLVED/i.test(text)) { return true; } // 空页面 if (document.body.innerHTML.trim() === '') { return true; } } return false; } // 替换 404 错误页面(幻境风格) function replace404Page() { const { errorCode, server } = extractErrorInfo(); document.documentElement.innerHTML = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>迷失幻境</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; } body { height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; position: relative; margin: 0; } /* 夜间模式(幻境风格) */ @media (prefers-color-scheme: dark) { body { background: radial-gradient(ellipse at center, #1a1a3a 0%, #0a0a1a 70%, #000000 100%); } .fog-layer { background: linear-gradient(45deg, rgba(74, 0, 224, 0.1), rgba(0, 210, 255, 0.1)); animation: fogFlow 20s infinite linear; } .mist { background: radial-gradient(circle, rgba(74, 0, 224, 0.2) 0%, rgba(74, 0, 224, 0) 70%); filter: blur(30px); } .fragment { border: 1px solid rgba(100, 100, 255, 0.3); box-shadow: 0 0 20px rgba(74, 0, 224, 0.4); } .star-dust { background: #b8b8ff; } .ripple { border: 2px solid rgba(100, 100, 255, 0.2); box-shadow: 0 0 20px rgba(74, 0, 224, 0.3); } .btn-particle { background: #b8b8ff; } h1, .icon, .error-code, .server { background: linear-gradient(135deg, #8e2de2, #4a00e0, #00d2ff); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 15px rgba(74, 0, 224, 0.5); } p { color: #b8b8ff; text-shadow: 0 0 10px rgba(74, 0, 224, 0.3); } .btn { background: linear-gradient(135deg, #4a00e0, #8e2de2); box-shadow: 0 4px 15px rgba(74, 0, 224, 0.4); } .btn:hover { box-shadow: 0 8px 20px rgba(74, 0, 224, 0.6); } } /* 白天模式(幻境风格) */ @media (prefers-color-scheme: light) { body { background: radial-gradient(ellipse at center, #e6e6fa 0%, #f0f0ff 70%, #ffffff 100%); } .fog-layer { background: linear-gradient(45deg, rgba(79, 209, 197, 0.1), rgba(246, 224, 94, 0.1)); animation: fogFlow 20s infinite linear; } .mist { background: radial-gradient(circle, rgba(246, 224, 94, 0.3) 0%, rgba(246, 224, 94, 0) 70%); filter: blur(25px); } .fragment { border: 1px solid rgba(79, 209, 197, 0.3); box-shadow: 0 0 20px rgba(246, 224, 94, 0.4); } .star-dust { background: #f6e05e; } .ripple { border: 2px solid rgba(79, 209, 197, 0.2); box-shadow: 0 0 20px rgba(246, 224, 94, 0.3); } .btn-particle { background: #f6e05e; } h1, .icon, .error-code, .server { background: linear-gradient(135deg, #4fd1c5, #f6e05e, #63b3ed); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 15px rgba(246, 224, 94, 0.5); } p { color: #2d3748; text-shadow: 0 0 10px rgba(246, 224, 94, 0.3); } .btn { background: linear-gradient(135deg, #4fd1c5, #f6e05e); box-shadow: 0 4px 15px rgba(79, 209, 197, 0.3); } .btn:hover { box-shadow: 0 8px 20px rgba(79, 209, 197, 0.5); } } /* 幻境元素 */ .fog-layer { position: absolute; width: 200%; height: 200%; top: -50%; left: -50%; opacity: 0.3; z-index: 0; } .mist { position: absolute; width: 200px; height: 200px; border-radius: 50%; animation: float 12s infinite ease-in-out; opacity: 0.5; z-index: 1; } .mist:nth-child(2) { top: 20%; left: 30%; animation-delay: 0s; } .mist:nth-child(3) { top: 50%; left: 70%; width: 150px; height: 150px; animation-delay: 4s; } .mist:nth-child(4) { top: 80%; left: 40%; width: 180px; height: 180px; animation-delay: 8s; } .fragment { position: absolute; background: transparent; opacity: 0.6; animation: float 15s infinite ease-in-out, rotate 10s infinite linear; z-index: 2; } .fragment.triangle { width: 0; height: 0; border-left: 20px solid transparent; border-right: 20px solid transparent; border-bottom: 35px solid rgba(255, 255, 255, 0.2); } .fragment.pentagon { width: 30px; height: 30px; clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%); background: rgba(255, 255, 255, 0.2); } .star-dust { position: absolute; width: 2px; height: 2px; border-radius: 50%; animation: drift 6s infinite ease-in-out; animation-delay: calc(var(--delay) * 1s); } .ripple { position: absolute; width: 100px; height: 100px; border-radius: 50%; opacity: 0; animation: ripple 5s infinite ease-out; z-index: 1; } .ripple:nth-child(2) { animation-delay: 0s; } .ripple:nth-child(3) { animation-delay: 1.5s; } .ripple:nth-child(4) { animation-delay: 3s; } .btn-particle { position: absolute; width: 3px; height: 3px; border-radius: 50%; animation: orbit 4s infinite ease-in-out; z-index: 3; } .content { position: relative; z-index: 3; text-align: center; animation: fadeIn 1s ease-out; } .icon-wrapper { position: relative; display: inline-block; } .error-code, .server { font-size: 18px; margin: 8px 0; animation: float 6s infinite ease-in-out; } .server { font-size: 14px; } h1 { font-size: 28px; font-weight: 600; margin: 0 0 12px; animation: gradientShift 8s ease infinite; background-size: 200% 200%; } p { font-size: 16px; line-height: 1.5; margin: 0 0 20px; } .btn-wrapper { position: relative; display: inline-block; } .btn { padding: 10px 24px; font-size: 14px; font-weight: 500; color: #ffffff; border: none; border-radius: 30px; cursor: pointer; transition: all 0.3s ease; animation: pulse 2s infinite; } .btn:hover { transform: translateY(-3px); } .icon { font-size: 48px; margin-bottom: 16px; animation: breathe 3s infinite ease-in-out; } @keyframes fogFlow { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } } @keyframes float { 0% { transform: translate(0, 0); } 33% { transform: translate(5px, 10px); } 66% { transform: translate(-5px, -10px); } 100% { transform: translate(0, 0); } } @keyframes rotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes drift { 0% { transform: translate(0, 0); opacity: 0.3; } 50% { transform: translate(20px, -10px); opacity: 1; } 100% { transform: translate(0, 0); opacity: 0.3; } } @keyframes ripple { 0% { width: 100px; height: 100px; opacity: 0.5; transform: translate(-50%, -50%); } 100% { width: 300px; height: 300px; opacity: 0; transform: translate(-50%, -50%); } } @keyframes orbit { 0% { transform: translate(0, 0); opacity: 0.5; } 50% { transform: translate(15px, 10px); opacity: 1; } 100% { transform: translate(0, 0); opacity: 0.5; } } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes breathe { 0% { opacity: 0.7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.2); } 100% { opacity: 0.7; transform: scale(1); } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @media (max-width: 600px) { h1 { font-size: 24px; } p { font-size: 14px; } .btn { padding: 8px 20px; font-size: 13px; } .icon { font-size: 40px; } .error-code { font-size: 16px; } .server { font-size: 12px; } .fragment.triangle { border-left: 15px solid transparent; border-right: 15px solid transparent; border-bottom: 25px solid rgba(255, 255, 255, 0.2); } .fragment.pentagon { width: 20px; height: 20px; } .ripple { width: 80px; height: 80px; } @keyframes ripple { 0% { width: 80px; height: 80px; opacity: 0.5; transform: translate(-50%, -50%); } 100% { width: 200px; height: 200px; opacity: 0; transform: translate(-50%, -50%); } } } </style> </head> <body> <!-- 流动迷雾层 --> <div class="fog-layer"></div> <!-- 迷雾效果 --> <div class="mist"></div> <div class="mist"></div> <div class="mist"></div> <!-- 幻境碎片 --> <div class="fragment triangle" style="top: 15%; left: 20%; animation-delay: 0s;"></div> <div class="fragment pentagon" style="top: 25%; left: 80%; animation-delay: 2s;"></div> <div class="fragment triangle" style="top: 70%; left: 30%; animation-delay: 4s;"></div> <div class="fragment pentagon" style="top: 60%; left: 85%; animation-delay: 6s;"></div> <div class="fragment triangle" style="top: 40%; left: 10%; animation-delay: 8s;"></div> <div class="fragment pentagon" style="top: 20%; left: 50%; animation-delay: 10s;"></div> <div class="fragment triangle" style="top: 80%; left: 70%; animation-delay: 12s;"></div> <!-- 中心涟漪 --> <div class="ripple" style="top: 50%; left: 50%;"></div> <div class="ripple" style="top: 50%; left: 50%;"></div> <div class="ripple" style="top: 50%; left: 50%;"></div> <!-- 中心内容 --> <div class="content"> <div class="icon-wrapper"> <div class="icon">✨</div> <div class="btn-particle" style="animation-delay: 0s;"></div> <div class="btn-particle" style="animation-delay: 1s;"></div> <div class="btn-particle" style="animation-delay: 2s;"></div> </div> <h1>迷失幻境</h1> <div class="error-code">${errorCode}</div> <div class="server">${server}</div> <p>路径已断,迷雾笼罩,尝试返回现实吧。</p> <div class="btn-wrapper"> <button class="btn" onclick="history.back()">返回现实</button> <div class="btn-particle" style="animation-delay: 0s;"></div> <div class="btn-particle" style="animation-delay: 1s;"></div> <div class="btn-particle" style="animation-delay: 2s;"></div> </div> </div> <script> // 随机星尘粒子 function addStarDust() { for (let i = 0; i < 50; i++) { const dust = document.createElement('div'); dust.className = 'star-dust'; dust.style.left = Math.random() * 100 + '%'; dust.style.top = Math.random() * 100 + '%'; dust.style.setProperty('--delay', Math.random() * 4); document.body.appendChild(dust); } } addStarDust(); // 监听主题切换 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { document.querySelectorAll('.star-dust').forEach(dust => dust.remove()); addStarDust(); }); </script> </body> </html> `; } // 替换网络连接失败页面(科幻风格,生命美学日间模式) function replaceConnectionErrorPage(errorUrl) { document.documentElement.innerHTML = ` <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>连接中断</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; } body { height: 100vh; display: flex; justify-content: center; align-items: center; color: #e0e0ff; overflow: hidden; position: relative; margin: 0; } /* 夜间模式(科幻风格) */ @media (prefers-color-scheme: dark) { body { background: radial-gradient(ellipse at center, #1a1a3a 0%, #0a0a1a 70%, #000000 100%); } .stars { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: transparent url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="0.5" fill="white" opacity="0.8"/></svg>') repeat; z-index: 1; } .star { position: absolute; width: 2px; height: 2px; background: white; border-radius: 50%; animation: twinkle 4s infinite; animation-delay: calc(var(--delay) * 1s); } .big-dipper { position: fixed; top: 10%; left: 5%; width: 100px; height: 60px; z-index: 1; } .big-dipper-star { position: absolute; width: 3px; height: 3px; background: #b8b8ff; border-radius: 50%; animation: twinkle 3s infinite; } .big-dipper-star:nth-child(1) { left: 20px; top: 10px; } .big-dipper-star:nth-child(2) { left: 35px; top: 15px; } .big-dipper-star:nth-child(3) { left: 50px; top: 20px; } .big-dipper-star:nth-child(4) { left: 65px; top: 25px; } .big-dipper-star:nth-child(5) { left: 55px; top: 40px; } .big-dipper-star:nth-child(6) { left: 45px; top: 50px; } .big-dipper-star:nth-child(7) { left: 35px; top: 60px; } .tao-flow { background: radial-gradient(circle, rgba(74, 0, 224, 0.3) 0%, rgba(74, 0, 224, 0) 70%); filter: blur(20px); } .container { background: rgba(10, 10, 30, 0.8); backdrop-filter: blur(10px); border: 1px solid rgba(100, 100, 255, 0.2); box-shadow: 0 8px 30px rgba(74, 0, 224, 0.3); } h1, .icon { background: linear-gradient(135deg, #8e2de2, #4a00e0, #00d2ff); -webkit-background-clip: text; background-clip: text; color: transparent; } p { color: #b8b8ff; } .btn { background: linear-gradient(135deg, #4a00e0, #8e2de2); box-shadow: 0 4px 15px rgba(74, 0, 224, 0.4); } .btn:hover { box-shadow: 0 8px 20px rgba(74, 0, 224, 0.6); } .failed-url { background: rgba(20, 20, 50, 0.5); color: #b8b8ff; } .error-code { color: #8888cc; } } /* 白天模式(生命美学风格,基于 1.8 版本) */ @media (prefers-color-scheme: light) { body { background: radial-gradient(ellipse at center, #e8f5e9 0%, #f1f8e9 70%, #ffffff 100%); /* 浅绿到白色,模拟自然光晕 */ } .stars { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: transparent url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><circle cx="50" cy="50" r="0.5" fill="#c8e6c9" opacity="0.4"/></svg>') repeat; /* 淡绿星点 */ z-index: 1; animation: twinkle 6s infinite alternate; } .tao-flow { background: radial-gradient(circle, rgba(165, 214, 167, 0.3) 0%, rgba(255, 245, 157, 0) 70%); /* 淡绿到浅金色 */ filter: blur(15px); } .tao-flow:nth-child(2) { top: 20%; left: 50%; width: 150px; height: 150px; animation-delay: 3s; transform: translateX(-50%); } .tao-flow:nth-child(3) { top: 50%; left: 50%; width: 180px; height: 180px; animation-delay: 6s; transform: translateX(-50%); } .container { background: rgba(255, 255, 255, 0.85); /* 更柔和的透明效果 */ backdrop-filter: blur(12px); border: 1px solid rgba(165, 214, 167, 0.3); /* 淡绿边框 */ box-shadow: 0 8px 30px rgba(165, 214, 167, 0.2); /* 淡绿阴影 */ } h1, .icon { background: linear-gradient(135deg, #a5d6a7, #fff59d, #aed581); /* 淡绿到浅金色渐变 */ -webkit-background-clip: text; background-clip: text; color: transparent; } p { color: #37474f; /* 深灰色文字 */ } .btn { background: linear-gradient(135deg, #a5d6a7, #fff59d); /* 淡绿到浅金色按钮 */ box-shadow: 0 4px 15px rgba(165, 214, 167, 0.3); } .btn:hover { box-shadow: 0 8px 20px rgba(165, 214, 167, 0.5); } .failed-url { background: rgba(240, 244, 195, 0.5); /* 浅金色背景 */ color: #455a64; /* 深灰色文字 */ } .error-code { color: #78909c; /* 浅灰色 */ } } /* 通用样式(科幻风格) */ .tao-flow { position: absolute; width: 200px; height: 200px; border-radius: 50%; animation: float 12s infinite ease-in-out; opacity: 0.6; z-index: 2; } .container { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 3; text-align: center; padding: 24px; border-radius: 16px; width: 90%; max-width: 400px; animation: fadeIn 0.6s ease-out; } h1 { font-size: 26px; font-weight: 600; margin: 0 0 12px; animation: gradientShift 8s ease infinite; background-size: 200% 200%; } p { font-size: 15px; line-height: 1.5; margin: 0 0 20px; } .btn { display: inline-block; padding: 10px 24px; font-size: 14px; font-weight: 500; color: #ffffff; border: none; border-radius: 30px; cursor: pointer; transition: all 0.3s ease; } .btn:hover { transform: translateY(-3px); } .failed-url { font-size: 13px; margin: 16px 0; padding: 8px 12px; border-radius: 8px; word-break: break-all; } .error-code { font-size: 12px; margin-top: 12px; } .icon { font-size: 48px; margin-bottom: 16px; animation: pulse 2s infinite; } @keyframes twinkle { 0% { opacity: 0.3; } 50% { opacity: 1; } 100% { opacity: 0.3; } } @keyframes float { 0% { transform: translate(0, 0); } 33% { transform: translate(30px, 30px); } 66% { transform: translate(-30px, -20px); } 100% { transform: translate(0, 0); } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @media (max-width: 600px) { .container { padding: 16px; width: 90%; max-width: 340px; left: 50%; transform: translate(-50%, -50%); } h1 { font-size: 22px; } p { font-size: 14px; } .btn { padding: 8px 20px; font-size: 13px; } .icon { font-size: 40px; } .big-dipper { width: 80px; height: 48px; } } </style> </head> <body> <div class="stars"></div> <div class="big-dipper"> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> <div class="big-dipper-star"></div> </div> <div class="tao-flow"></div> <div class="tao-flow"></div> <div class="container"> <div class="icon">⚡️</div> <h1>连接中断</h1> <p>无法感知星辰脉动,请检查网络或稍后重试。</p> <button class="btn" onclick="window.location.reload()">重新连接</button> <div class="failed-url">目标地址: ${errorUrl}</div> <div class="error-code">错误代码: net::ERR_CONNECTION_ABORTED</div> </div> <script> // 随机星星闪烁 function addRandomStars() { if (window.matchMedia('(prefers-color-scheme: dark)').matches) { for (let i = 0; i < 20; i++) { const star = document.createElement('div'); star.className = 'star'; star.style.left = Math.random() * 100 + 'vw'; star.style.top = Math.random() * 100 + 'vh'; star.style.setProperty('--delay', Math.random() * 4); document.body.appendChild(star); } } } addRandomStars(); // 监听主题切换 window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { document.querySelectorAll('.star').forEach(star => star.remove()); addRandomStars(); }); </script> </body> </html> `; } // 快速注入机制 function initInjection() { // 优先检查 404 页面 if (checkFor404Page()) { replace404Page(); return true; } // 再检查网络连接失败页面 if (checkForConnectionErrorPage()) { const errorUrl = extractErrorUrl(); replaceConnectionErrorPage(errorUrl); return true; } return false; } // 立即检查 initInjection(); // 早期高频检查 let attempts = 0; const maxAttempts = 20; // 最多检查 1 秒(50ms x 20) const earlyCheckInterval = setInterval(() => { if (initInjection()) { clearInterval(earlyCheckInterval); } else if (attempts >= maxAttempts) { clearInterval(earlyCheckInterval); } attempts++; }, 50); // 监听 DOM 变化 const observer = new MutationObserver((mutations, obs) => { if (initInjection()) { obs.disconnect(); } }); // 尽早观察 documentElement observer.observe(document.documentElement, { childList: true, subtree: true }); // 页面加载完成时再检查 document.addEventListener('DOMContentLoaded', () => { initInjection(); }, { once: true }); })();