Greasy Fork

Greasy Fork is available in English.

视频字幕遮罩条

创建一个磨砂半透明遮罩条来遮挡视频字幕

当前为 2024-12-03 提交的版本,查看 最新版本

// ==UserScript==
// @name         视频字幕遮罩条
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  创建一个磨砂半透明遮罩条来遮挡视频字幕
// @author       Aaron Hu
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 检查是否已经存在遮罩条
    if (document.querySelector('#subtitle-mask-container')) {
        console.log('遮罩条已存在');
        return;
    }

    // 创建容器和遮罩条
    const container = document.createElement('div');
    container.id = 'subtitle-mask-container'; // 为容器添加唯一ID
    const mask = document.createElement('div');

    // 创建关闭按钮
    const closeButton = document.createElement('div');
    closeButton.innerHTML = '×'; // 使用乘号符号作为关闭按钮
    Object.assign(closeButton.style, {
        position: 'absolute',
        top: '5px',
        right: '5px',
        width: '20px',
        height: '20px',
        backgroundColor: 'rgba(255, 255, 255, 0.7)',
        color: 'black',
        textAlign: 'center',
        lineHeight: '20px',
        borderRadius: '50%',
        cursor: 'pointer',
        zIndex: '2147483648', // 确保在遮罩条之上
    });

    // 添加关闭按钮的点击事件
    closeButton.addEventListener('click', () => {
        container.remove();
        GM_setValue('maskVisible', false); // 更新存储状态
    });

    // 将关闭按钮添加到遮罩条
    mask.appendChild(closeButton);

    // 从存储中获取显示状态和位置信息
    let isVisible = GM_getValue('maskVisible', false);
    let maskConfig = GM_getValue('maskConfig', {
        width: '80%',
        height: '80px',
        bottom: '30px',
        xOffset: 0
    });

    // 设置容器样式
    Object.assign(container.style, {
        position: 'fixed',
        top: '0',
        left: '0',
        width: '100%',
        height: '100%',
        zIndex: '2147483647',
        pointerEvents: 'none',
        display: isVisible ? 'block' : 'none'
    });

    // 设置遮罩条的样式
    Object.assign(mask.style, {
        position: 'fixed',
        bottom: maskConfig.bottom,
        left: '50%',
        transform: `translateX(calc(-50% + ${maskConfig.xOffset}px))`,
        width: maskConfig.width,
        height: maskConfig.height,
        backgroundColor: 'rgba(255, 255, 255, 0.2)',
        backdropFilter: 'blur(8px)',
        zIndex: '2147483647',
        cursor: 'move',
        border: '1px solid rgba(255, 255, 255, 0.1)',
        borderRadius: '4px',
        pointerEvents: 'auto',
        userSelect: 'none',
    });

    // 添加切换显示状态的函数
    function toggleMask() {
        isVisible = !isVisible;
        GM_setValue('maskVisible', isVisible);
        container.style.display = isVisible ? 'block' : 'none';
    }

    // 注册油猴菜单命令
    GM_registerMenuCommand('切换遮罩条显示', toggleMask);

    // 监听油猴脚本的启用/禁用状态
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.attributeName === 'disabled') {
                const scriptTag = document.querySelector('script[src*="subtitle-mask.user.js"]');
                if (scriptTag) {
                    const isEnabled = !scriptTag.hasAttribute('disabled');
                    container.style.display = isEnabled && isVisible ? 'block' : 'none';
                }
            }
        });
    });

    // 观察脚本标签的变化
    const scriptTag = document.querySelector('script[src*="subtitle-mask.user.js"]');
    if (scriptTag) {
        observer.observe(scriptTag, {
            attributes: true,
            attributeFilter: ['disabled']
        });
    }

    // 修改拖动功能的代码部分
    let isDragging = false;
    let currentX, currentY;
    let initialX, initialY;
    let xOffset = 0, yOffset = 0;

    mask.addEventListener('mousedown', dragStart);
    document.addEventListener('mousemove', drag);
    document.addEventListener('mouseup', dragEnd);

    function dragStart(e) {
        // 记录鼠标按下时的初始位置
        const rect = mask.getBoundingClientRect();
        xOffset = rect.left + rect.width / 2;  // 考虑元素的中心点
        yOffset = window.innerHeight - rect.top - rect.height / 2;  // 从底部计算偏移

        initialX = e.clientX - (rect.left + rect.width / 2);
        initialY = e.clientY - (rect.top + rect.height / 2);

        isDragging = true;
    }

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

        // 计算新位置
        const x = e.clientX - initialX - window.innerWidth / 2;
        const y = window.innerHeight - (e.clientY - initialY) - mask.offsetHeight / 2;

        // 更新位置
        mask.style.left = '50%';
        mask.style.bottom = `${y}px`;
        mask.style.transform = `translate(calc(-50% + ${x}px), 0)`;

        // 保存位置信息
        maskConfig.bottom = `${y}px`;
        maskConfig.xOffset = x;
        GM_setValue('maskConfig', maskConfig);
    }

    function dragEnd() {
        isDragging = false;
    }

    // 添加左右两侧的宽度调节器
    const leftResizer = document.createElement('div');
    const rightResizer = document.createElement('div');

    // 设置调节器的基础样式
    const resizerStyles = {
        position: 'absolute',
        top: '0',
        width: '10px',
        height: '100%',
        backgroundColor: 'rgba(255, 255, 255, 0.3)',
        cursor: 'ew-resize',
        borderRadius: '4px',
    };

    // 设置左侧调节器
    Object.assign(leftResizer.style, {
        ...resizerStyles,
        left: '-5px',
    });

    // 设置右侧调节器
    Object.assign(rightResizer.style, {
        ...resizerStyles,
        right: '-5px',
    });

    // 宽度调节相关变量
    let isResizingWidth = false;
    let resizingSide = null;
    let initialWidth;
    let initialMouseX;

    // 开始调节宽度
    function widthResizeStart(e, side) {
        isResizingWidth = true;
        resizingSide = side;
        initialWidth = mask.offsetWidth;
        initialMouseX = e.clientX;
        e.stopPropagation();
    }

    // 调节宽度过程
    function widthResize(e) {
        if (!isResizingWidth) return;
        e.preventDefault();

        const deltaX = e.clientX - initialMouseX;
        const newWidth = resizingSide === 'right'
            ? initialWidth + deltaX
            : initialWidth - deltaX;

        // 设置最小宽度限制为100px
        if (newWidth > 100) {
            mask.style.width = `${newWidth}px`;
            if (resizingSide === 'left') {
                // 左侧调节时保持中心点不变
                const xAdjustment = deltaX / 2;
                mask.style.transform = `translateX(calc(-50% + ${xAdjustment}px))`;
                maskConfig.xOffset = xAdjustment;
            }
            maskConfig.width = `${newWidth}px`;
            GM_setValue('maskConfig', maskConfig);
        }
    }

    // 结束调节宽度
    function widthResizeEnd() {
        isResizingWidth = false;
        resizingSide = null;
    }

    // 添加事件监听
    leftResizer.addEventListener('mousedown', (e) => widthResizeStart(e, 'left'));
    rightResizer.addEventListener('mousedown', (e) => widthResizeStart(e, 'right'));
    document.addEventListener('mousemove', widthResize);
    document.addEventListener('mouseup', widthResizeEnd);

    // 将调节器添加到遮罩条
    mask.appendChild(leftResizer);
    mask.appendChild(rightResizer);

    // 在宽度调节器代码后添加高度调节器代码
    const heightResizer = document.createElement('div');

    // 设置高度调节器的样式
    Object.assign(heightResizer.style, {
        position: 'absolute',
        top: '-5px',
        left: '50%',
        transform: 'translateX(-50%)',
        width: '40px',
        height: '10px',
        backgroundColor: 'rgba(255, 255, 255, 0.3)',
        cursor: 'ns-resize',
        borderRadius: '4px',
    });

    // 高度调节相关变量
    let isResizingHeight = false;
    let initialHeight;
    let initialMouseY;

    // 开始调节高度
    function heightResizeStart(e) {
        isResizingHeight = true;
        initialHeight = mask.offsetHeight;
        initialMouseY = e.clientY;
        e.stopPropagation();
    }

    // 调节高度过程
    function heightResize(e) {
        if (!isResizingHeight) return;
        e.preventDefault();

        const deltaY = initialMouseY - e.clientY;
        const newHeight = initialHeight + deltaY;

        // 设置最小高度限制为20px
        if (newHeight > 20) {
            mask.style.height = `${newHeight}px`;
            maskConfig.height = `${newHeight}px`;
            GM_setValue('maskConfig', maskConfig);
        }
    }

    // 结束调节高度
    function heightResizeEnd() {
        isResizingHeight = false;
    }

    // 添加高度调节相关的事件监听
    heightResizer.addEventListener('mousedown', heightResizeStart);
    document.addEventListener('mousemove', heightResize);
    document.addEventListener('mouseup', heightResizeEnd);

    // 将高度调节器添加到遮罩条
    mask.appendChild(heightResizer);

    // 确保遮罩条立即显示
    container.style.display = isVisible ? 'block' : 'none';
    container.appendChild(mask);
    document.body.appendChild(container);

    // 添加调试信息
    console.log('遮罩条已创建', {
        isVisible,
        containerDisplay: container.style.display,
        maskStyles: mask.style,
        containerStyles: container.style
    });

    // 添加全屏检测和处理
    document.addEventListener('fullscreenchange', handleFullscreen);
    document.addEventListener('webkitfullscreenchange', handleFullscreen);
    document.addEventListener('mozfullscreenchange', handleFullscreen);
    document.addEventListener('MSFullscreenChange', handleFullscreen);

    function handleFullscreen() {
        const fullscreenElement = document.fullscreenElement || 
                                 document.webkitFullscreenElement || 
                                 document.mozFullScreenElement || 
                                 document.msFullscreenElement;
        
        if (fullscreenElement) {
            // 在全屏元素内重新添加遮罩
            fullscreenElement.appendChild(container);
        } else {
            // 退出全屏时重新添加到 body
            document.body.appendChild(container);
        }
    }
})();