Subtitle Overlay Tool 字幕遮罩工具

Create a draggable, resizable overlay to cover subtitles on any website

目前為 2025-08-17 提交的版本,檢視 最新版本

// ==UserScript==
// @license MIT
// @name         Subtitle Overlay Tool 字幕遮罩工具
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Create a draggable, resizable overlay to cover subtitles on any website
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let overlay = null;
    let isVisible = false;
    let isDragging = false;
    let isResizing = false;
    let dragOffset = { x: 0, y: 0 };
    let resizeStartSize = { width: 0, height: 0 };
    let resizeStartMouse = { x: 0, y: 0 };
    let opacity = 1.0; // Start fully opaque

    // Create the overlay element
    function createOverlay() {
        overlay = document.createElement('div');
        overlay.id = 'subtitle-overlay';
        overlay.style.cssText = `
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            width: 400px;
            height: 100px;
            background-color: rgba(0, 0, 0, 1.0);
            border: 2px solid #333;
            border-radius: 8px;
            cursor: move;
            z-index: 2147483647;
            display: none;
            user-select: none;
            box-sizing: border-box;
        `;

        // Create resize handle
        const resizeHandle = document.createElement('div');
        resizeHandle.style.cssText = `
            position: absolute;
            bottom: 0;
            right: 0;
            width: 20px;
            height: 20px;
            background-color: rgba(255, 255, 255, 0.3);
            cursor: se-resize;
            border-radius: 0 0 8px 0;
        `;
        overlay.appendChild(resizeHandle);

        // Create close button
        const closeButton = document.createElement('div');
        closeButton.innerHTML = '×';
        closeButton.style.cssText = `
            position: absolute;
            top: 5px;
            right: 8px;
            width: 20px;
            height: 20px;
            color: white;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            text-align: center;
            line-height: 20px;
            border-radius: 50%;
            background-color: rgba(255, 255, 255, 0.1);
            opacity: 0.7;
            transition: opacity 0.2s;
        `;
        closeButton.onmouseover = () => closeButton.style.opacity = '1';
        closeButton.onmouseout = () => closeButton.style.opacity = '0.7';
        closeButton.onclick = hideOverlay;
        overlay.appendChild(closeButton);

        // Create info text
        const infoText = document.createElement('div');
        infoText.innerHTML = 'Subtitle Blocker<br><small>Drag to move • Resize from corner • Scroll to adjust opacity • Ctrl+B to toggle</small>';
        infoText.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: rgba(255, 255, 255, 0.6);
            text-align: center;
            font-family: Arial, sans-serif;
            font-size: 12px;
            pointer-events: none;
        `;
        overlay.appendChild(infoText);

        document.body.appendChild(overlay);
        attachEventListeners();
        handleFullscreenEvents();
    }

    function updateOpacity() {
        if (overlay) {
            overlay.style.backgroundColor = `rgba(0, 0, 0, ${opacity})`;
        }
    }

    function handleFullscreenEvents() {
        // Listen for fullscreen changes
        document.addEventListener('fullscreenchange', handleFullscreenChange);
        document.addEventListener('webkitfullscreenchange', handleFullscreenChange);
        document.addEventListener('mozfullscreenchange', handleFullscreenChange);
        document.addEventListener('MSFullscreenChange', handleFullscreenChange);
    }

    function handleFullscreenChange() {
        if (!overlay || !isVisible) return;

        // Get the fullscreen element
        const fullscreenElement = document.fullscreenElement ||
                                document.webkitFullscreenElement ||
                                document.mozFullScreenElement ||
                                document.msFullscreenElement;

        if (fullscreenElement) {
            // Entering fullscreen - move overlay to fullscreen element
            try {
                fullscreenElement.appendChild(overlay);
                // Ensure overlay maintains its properties in fullscreen
                overlay.style.position = 'absolute';
                overlay.style.zIndex = '2147483647';
            } catch (e) {
                // Fallback: keep in body but ensure maximum z-index
                overlay.style.position = 'fixed';
                overlay.style.zIndex = '2147483647';
            }
        } else {
            // Exiting fullscreen - move overlay back to body
            if (overlay.parentNode !== document.body) {
                document.body.appendChild(overlay);
            }
            overlay.style.position = 'fixed';
            overlay.style.zIndex = '2147483647';
        }
    }

    function attachEventListeners() {
        const resizeHandle = overlay.querySelector('div:first-child');

        // Mouse down on overlay (start dragging)
        overlay.addEventListener('mousedown', function(e) {
            if (e.target === resizeHandle) {
                startResize(e);
            } else if (e.target !== overlay.querySelector('div:nth-child(2)')) { // Not the close button
                startDrag(e);
            }
        });

        // Mouse move
        document.addEventListener('mousemove', function(e) {
            if (isDragging) {
                drag(e);
            } else if (isResizing) {
                resize(e);
            }
        });

        // Mouse up
        document.addEventListener('mouseup', function() {
            isDragging = false;
            isResizing = false;
        });

        // Prevent text selection while dragging
        document.addEventListener('selectstart', function(e) {
            if (isDragging || isResizing) {
                e.preventDefault();
            }
        });

        // Scroll wheel opacity adjustment
        overlay.addEventListener('wheel', function(e) {
            e.preventDefault();
            e.stopPropagation();

            const delta = e.deltaY > 0 ? -0.05 : 0.05;
            opacity = Math.max(0.1, Math.min(1.0, opacity + delta));
            updateOpacity();
        });
    }

    function startDrag(e) {
        isDragging = true;
        const rect = overlay.getBoundingClientRect();
        dragOffset.x = e.clientX - rect.left;
        dragOffset.y = e.clientY - rect.top;
        overlay.style.cursor = 'grabbing';
    }

    function drag(e) {
        if (!isDragging) return;

        const x = e.clientX - dragOffset.x;
        const y = e.clientY - dragOffset.y;

        // Keep overlay within viewport bounds
        const maxX = window.innerWidth - overlay.offsetWidth;
        const maxY = window.innerHeight - overlay.offsetHeight;

        const boundedX = Math.max(0, Math.min(x, maxX));
        const boundedY = Math.max(0, Math.min(y, maxY));

        overlay.style.left = boundedX + 'px';
        overlay.style.top = boundedY + 'px';
        overlay.style.transform = 'none';
    }

    function startResize(e) {
        e.stopPropagation();
        isResizing = true;
        resizeStartSize.width = overlay.offsetWidth;
        resizeStartSize.height = overlay.offsetHeight;
        resizeStartMouse.x = e.clientX;
        resizeStartMouse.y = e.clientY;
    }

    function resize(e) {
        if (!isResizing) return;

        const deltaX = e.clientX - resizeStartMouse.x;
        const deltaY = e.clientY - resizeStartMouse.y;

        const newWidth = Math.max(100, resizeStartSize.width + deltaX);
        const newHeight = Math.max(50, resizeStartSize.height + deltaY);

        overlay.style.width = newWidth + 'px';
        overlay.style.height = newHeight + 'px';
    }

    function showOverlay() {
        if (!overlay) createOverlay();
        overlay.style.display = 'block';
        isVisible = true;
    }

    function hideOverlay() {
        if (overlay) {
            overlay.style.display = 'none';
            overlay.style.cursor = 'move';
        }
        isVisible = false;
        isDragging = false;
        isResizing = false;
    }

    function toggleOverlay() {
        if (isVisible) {
            hideOverlay();
        } else {
            showOverlay();
        }
    }

    // Keyboard shortcut listener
    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.key.toLowerCase() === 'b') {
            e.preventDefault();
            toggleOverlay();
        }
    });

    // Initialize
    console.log('Subtitle Overlay Tool loaded. Press Ctrl+B to toggle overlay. Scroll over overlay to adjust opacity.');
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址