Via浏览器苦力怕论坛去重定向脚本
本脚本使用DeepSeek编写,代码如下,请自行添加脚本// ==UserScript==// @name KLPBBS 去重定向
// @namespace https://klpbbs.com/
// @version 1.3
// @Description去除 klpbbs.com 的 url.php 重定向,点击站外链接时顶部显示圆角绿色横幅(滑入动画),倒计时跳动,自动隐藏后在新标签页打开链接。
// @Author Helper
// @MATCH *://klpbbs.com/*
// @match *://*.klpbbs.com/*
// @Grant none
// ==/UserScript==
(function() {
'use strict';
const SITE_DOMAIN = 'klpbbs.com';
let bannerTimeout = null;
let bannerInterval = null;
let bannerDiv = null;
let isClosing = false; // 防止重复关闭
// 获取域名(用于横幅显示)
function getHostname(url) {
try {
const a = document.createElement('a');
a.href = url;
return a.hostname;
} catch(e) {
return '';
}
}
// 关闭横幅(带退场动画)
function closeBanner(doJump, targetUrl) {
if (!bannerDiv || isClosing) return;
isClosing = true;
// 清除所有计时器
if (bannerTimeout) clearTimeout(bannerTimeout);
if (bannerInterval) clearInterval(bannerInterval);
// 添加退场动画类
bannerDiv.classList.add('banner-hide');
// 等待动画结束再移除横幅
const onTransitionEnd = () => {
bannerDiv.removeEventListener('transitionend', onTransitionEnd);
if (bannerDiv && bannerDiv.parentNode) bannerDiv.parentNode.removeChild(bannerDiv);
bannerDiv = null;
isClosing = false;
// 执行跳转(如果需要)
if (doJump && targetUrl && !targetUrl.startsWith('javascript:')) {
window.open(targetUrl, '_blank');
}
};
bannerDiv.addEventListener('transitionend', onTransitionEnd, { once: true });
// 防止某些情况下transitionend不触发,设置后备定时器
setTimeout(() => {
if (bannerDiv && bannerDiv.parentNode) {
bannerDiv.removeEventListener('transitionend', onTransitionEnd);
bannerDiv.parentNode.removeChild(bannerDiv);
bannerDiv = null;
isClosing = false;
if (doJump && targetUrl && !targetUrl.startsWith('javascript:')) {
window.open(targetUrl, '_blank');
}
}
}, 500);
}
// 显示绿色横幅(动画版)
function showBanner(targetUrl) {
if (bannerDiv) closeBanner(false); // 如果有旧横幅,先关闭(无跳转)
// 创建横幅元素
bannerDiv = document.createElement('div');
bannerDiv.id = 'ext-link-banner';
bannerDiv.className = 'banner-show'; // 初始无动画,稍后添加入场类
bannerDiv.style.cssText = `
position: fixed;
top: 10px;
left: 10px;
right: 10px;
background-color: #4caf50;
color: white;
text-align: center;
padding: 12px 40px 12px 20px;
font-size: 16px;
z-index: 999999;
font-family: sans-serif;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
border-radius: 12px;
cursor: default;
backdrop-filter: blur(2px);
transform: translateY(-120%);
opacity: 0;
transition: transform 0.25s cubic-bezier(0.2, 0.9, 0.4, 1.1), opacity 0.2s ease;
`;
// 创建内容容器
const contentSpan = document.createElement('span');
const host = getHostname(targetUrl);
contentSpan.innerHTML = `即将跳转到外部网站:${host},<span id="countdown-num" style="display:inline-block; min-width:24px;">3</span> 秒后自动在新标签页打开...`;
// 取消按钮
const closeBtn = document.createElement('span');
closeBtn.textContent = '✕ 取消';
closeBtn.style.cssText = `
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
background-color: rgba(0,0,0,0.2);
padding: 4px 10px;
border-radius: 20px;
font-size: 14px;
transition: background-color 0.2s;
`;
closeBtn.onmouseover = () => closeBtn.style.backgroundColor = 'rgba(0,0,0,0.35)';
closeBtn.onmouseout = () => closeBtn.style.backgroundColor = 'rgba(0,0,0,0.2)';
closeBtn.onclick = (e) => {
e.stopPropagation();
closeBanner(false); // 取消跳转
};
bannerDiv.appendChild(contentSpan);
bannerDiv.appendChild(closeBtn);
document.body.appendChild(bannerDiv);
// 强制重绘后添加入场动画类
requestAnimationFrame(() => {
bannerDiv.style.transform = 'translateY(0)';
bannerDiv.style.opacity = '1';
});
// 倒计时逻辑
let countdown = 3;
const countdownSpan = document.getElementById('countdown-num');
if (!countdownSpan) return; // 安全检测
// 跳动动画CSS(动态添加)
const styleId = 'countdown-bounce-style';
if (!document.getElementById(styleId)) {
const style = document.createElement('style');
style.id = styleId;
style.textContent = `
.countdown-bounce {
animation: bounceAnim 0.3s ease;
}
@keyframes bounceAnim {
0% { transform: scale(1); }
50% { transform: scale(1.4); color: #fff3b0; }
100% { transform: scale(1); }
}
`;
document.head.appendChild(style);
}
const updateCountdown = () => {
if (!countdownSpan || !bannerDiv) return;
countdownSpan.textContent = countdown;
countdownSpan.classList.add('countdown-bounce');
setTimeout(() => countdownSpan.classList.remove('countdown-bounce'), 300);
if (countdown <= 0) {
// 倒计时结束,关闭横幅并跳转
if (bannerInterval) clearInterval(bannerInterval);
closeBanner(true, targetUrl);
}
countdown--;
};
updateCountdown(); // 立即显示3
bannerInterval = setInterval(updateCountdown, 1000);
// 设置超时保护(防止interval意外不触发)
bannerTimeout = setTimeout(() => {
if (bannerInterval) clearInterval(bannerInterval);
closeBanner(true, targetUrl);
}, 3000);
}
// 从 url.php 提取真实链接
function extractRealUrl(url) {
if (url.includes('/url.php?url=')) {
try {
const urlObj = new URL(url);
const real = urlObj.searchParams.get('url');
if (real) return decodeURIComponent(real);
} catch(e) {}
}
return null;
}
// 判断是否为站外链接(不含重定向链接本身)
function isExternalLink(href) {
if (!href) return false;
if (href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) return false;
try {
const a = document.createElement('a');
a.href = href;
const linkHost = a.hostname;
if (!linkHost) return false;
if (linkHost === SITE_DOMAIN || linkHost.endsWith('.' + SITE_DOMAIN)) return false;
return true;
} catch(e) {
return false;
}
}
// 全局点击拦截(捕获阶段)
document.addEventListener('click', function(e) {
if (e.button !== 0) return; // 仅左键
if (e.ctrlKey || e.shiftKey || e.metaKey) return; // 保留新窗口快捷键
let target = e.target;
while (target && target.tagName !== 'A') target = target.parentElement;
if (!target || !target.href) return;
const href = target.href;
const real = extractRealUrl(href);
if (real) {
e.preventDefault();
e.stopPropagation();
showBanner(real);
return;
}
if (isExternalLink(href)) {
e.preventDefault();
e.stopPropagation();
showBanner(href);
}
}, true);
})();
页: [1]