Greasy Fork

Greasy Fork is available in English.

最强摸鱼插件

我说这个是广告,你信吗?

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         最强摸鱼插件
// @version      2.9
// @description 我说这个是广告,你信吗?
// @author       Gemini
// @match        *://*/*
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @run-at       document-idle
// @namespace http://greasyfork.icu/users/1470321
// ==/UserScript==

(function() {
    'use strict';

    // ----------------------------------------------------
    //                 【CSS 样式注入】
    // ----------------------------------------------------
    GM_addStyle(`
        /* 浮动按钮样式 */
        #fishing-settings-btn {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 30px;
            height: 30px;
            background-color: rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border: none;
            color: #fff;
            cursor: pointer;
            z-index: 99999;
            opacity: 0.1;
            transition: opacity 0.3s, background-color 0.3s;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            box-shadow: 0 0 5px rgba(0,0,0,0.3);
            text-align: center;
        }
        #fishing-settings-btn:hover {
            opacity: 1;
            background-color: rgba(0, 123, 255, 0.8);
        }
        /* 模态窗口样式 */
        #fishing-modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 100000;
            display: none;
            justify-content: center;
            align-items: center;
        }
        #fishing-modal-content {
            background: #fff;
            padding: 20px;
            border-radius: 8px;
            width: 90%;
            max-width: 400px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
            color: #333;
        }
        #fishing-modal-content input[type="url"] {
            width: 100%;
            padding: 8px;
            margin: 10px 0;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        #fishing-modal-content button {
            padding: 8px 15px;
            margin: 5px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        .fishing-modal-save { background-color: #007bff; color: white; }
        .fishing-modal-close { background-color: #6c757d; color: white; }

        /* 模拟图标 */
        #fishing-settings-btn::before {
            content: "⚙️";
        }

        /* 确保被替换的页尾 div 容器有足够的内边距 */
        .body-footer {
             padding-top: 20px;
             padding-bottom: 20px;
             text-align: center;
        }
    `);

    // --- 【兼容性封装】 ---
    const storage = {
        getValue: (key, defaultValue) => {
            if (typeof GM !== 'undefined' && typeof GM.getValue === 'function') {
                return GM.getValue(key, defaultValue);
            }
            else if (typeof GM_getValue === 'function') {
                return Promise.resolve(GM_getValue(key, defaultValue));
            }
            return Promise.resolve(defaultValue);
        },
        setValue: (key, value) => {
            if (typeof GM !== 'undefined' && typeof GM.setValue === 'function') {
                return GM.setValue(key, value);
            }
            else if (typeof GM_setValue === 'function') {
                GM_setValue(key, value);
                return Promise.resolve();
            }
            return Promise.resolve();
        }
    };


    // ----------------------------------------------------
    //                 【用户配置区域】
    // ----------------------------------------------------

    const TARGET_AD_CONTAINER_SELECTOR = '.body-footer';

    const DEFAULT_FISHING_PAGE_URL = 'https://en.wikipedia.org/wiki/Special:Random';
    const IFRAME_HEIGHT = '250px';
    const IFRAME_WIDTH = '100%';
    const STORAGE_KEY = 'fishing_page_url_vjudge';

    // ----------------------------------------------------
    //                 【脚本主体入口】
    // ----------------------------------------------------

    async function main() {

        let currentFishingUrl = await storage.getValue(STORAGE_KEY, DEFAULT_FISHING_PAGE_URL);

        // --- 1. 核心广告替换逻辑 ---

        function setupAdReplacement(fishingUrl) {
            const targetDiv = document.querySelector(TARGET_AD_CONTAINER_SELECTOR);

            if (!targetDiv) {
                console.log(`摸鱼脚本:未找到目标元素 ${TARGET_AD_CONTAINER_SELECTOR}。`);
                return;
            }

            // 清理目标div的内容 (替换整个标签的内容)
            targetDiv.innerHTML = '';

            // 状态变量:跟踪当前是否处于摸鱼模式(iframe可见)
            let isFishingMode = false;

            // 创建隐形占位符元素 (与 iframe 同高)
            const safePlaceholder = document.createElement('div');
            safePlaceholder.id = 'fishing-placeholder';
            safePlaceholder.style.width = IFRAME_WIDTH;
            safePlaceholder.style.height = IFRAME_HEIGHT;
            safePlaceholder.style.border = '0';
            safePlaceholder.style.backgroundColor = 'transparent';
            safePlaceholder.style.cursor = 'default';

            // 创建摸鱼用的 iframe 元素
            const fishingIframe = document.createElement('iframe');
            fishingIframe.id = 'fishing-iframe';
            fishingIframe.src = fishingUrl;
            fishingIframe.style.width = IFRAME_WIDTH;
            fishingIframe.style.height = IFRAME_HEIGHT;
            fishingIframe.style.border = '0';
            fishingIframe.style.margin = '0';
            fishingIframe.style.padding = '0';
            // 初始隐藏 iframe
            fishingIframe.style.display = 'none';

            // 将占位符和 iframe 都添加到容器中
            targetDiv.appendChild(safePlaceholder);
            targetDiv.appendChild(fishingIframe);

            // 调整样式以适应页尾
            targetDiv.style.textAlign = 'center';

            // --- 核心切换逻辑 ---
            function toggleFishingMode(e) {
                // 阻止事件冒泡到 document,避免点击 targetDiv 立即隐藏
                e.stopPropagation();

                if (isFishingMode) {
                    // 隐藏 iframe,显示占位符
                    fishingIframe.style.display = 'none';
                    safePlaceholder.style.display = 'block';
                    isFishingMode = false;
                    console.log('摸鱼脚本:切换到隐形模式。');
                } else {
                    // 显示 iframe,隐藏占位符
                    safePlaceholder.style.display = 'none';
                    fishingIframe.style.display = 'block';
                    // 确保 iframe 刷新内容
                    fishingIframe.src = fishingUrl;
                    isFishingMode = true;
                    console.log('摸鱼脚本:切换到摸鱼模式。');
                }
            }

            // 1. 点击目标区域 (body-footer) 切换模式
            targetDiv.onclick = toggleFishingMode;

            // 2. 点击页面其他任何地方时隐藏 iframe
            document.onclick = (e) => {
                // 如果当前处于摸鱼模式,且点击的不是设置按钮
                if (isFishingMode && e.target.id !== 'fishing-settings-btn') {
                    // 隐藏 iframe,显示占位符
                    fishingIframe.style.display = 'none';
                    safePlaceholder.style.display = 'block';
                    isFishingMode = false;
                    console.log('摸鱼脚本:点击页面其他地方,自动切换到隐形模式。');
                }
            };

            console.log(`摸鱼脚本:页尾点击切换已激活,当前摸鱼 URL: ${fishingUrl}`);
        }

        // --- 2. 右下角设置按钮和弹窗逻辑 ---

        // 创建按钮
        const settingsButton = document.createElement('button');
        settingsButton.id = 'fishing-settings-btn';
        settingsButton.title = '设置摸鱼URL';
        document.body.appendChild(settingsButton);

        // 创建模态窗口
        const modalOverlay = document.createElement('div');
        modalOverlay.id = 'fishing-modal-overlay';
        modalOverlay.innerHTML = `
            <div id="fishing-modal-content">
                <h4>摸鱼 URL 设置</h4>
                <p>请输入您希望在鼠标悬停时显示的页面 URL:</p>
                <input type="url" id="fishing-url-input" placeholder="例如: https://www.example.com/fish" value="${currentFishingUrl}">
                <button class="fishing-modal-save" id="fishing-save-btn">保存并刷新</button>
                <button class="fishing-modal-close" id="fishing-close-btn">关闭</button>
            </div>
        `;
        document.body.appendChild(modalOverlay);

        // 绑定事件
        settingsButton.onclick = (e) => {
            // 阻止冒泡,避免点击设置按钮时触发 document 隐藏逻辑
            e.stopPropagation();
            document.getElementById('fishing-url-input').value = currentFishingUrl;
            modalOverlay.style.display = 'flex';
        };

        document.getElementById('fishing-close-btn').onclick = () => {
            modalOverlay.style.display = 'none';
        };

        document.getElementById('fishing-save-btn').onclick = async () => {
            const inputElement = document.getElementById('fishing-url-input');
            const newUrl = inputElement.value.trim();

            if (newUrl && (newUrl.startsWith('http://') || newUrl.startsWith('https://'))) {
                currentFishingUrl = newUrl;
                await storage.setValue(STORAGE_KEY, newUrl);
                alert('新的摸鱼 URL 已保存!页面将刷新以应用更改。');
                modalOverlay.style.display = 'none';
                window.location.reload();
            } else {
                alert('请输入一个有效的 URL (必须以 http:// 或 https:// 开头)。');
                inputElement.focus();
            }
        };

        // --- 3. 页面加载后执行 ---
        window.addEventListener('load', () => {
            setupAdReplacement(currentFishingUrl);
        });
    }

    // 运行主函数
    main();

})();