coolskyyt l 发表于 2026-3-31 19:34:54

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]
查看完整版本: Via浏览器苦力怕论坛去重定向脚本