Greasy Fork

字幕遮挡条

毛玻璃效果的字幕遮挡条,如果你看美剧英剧且不想看中文字幕的话,且快捷键V键可以快速启动

目前为 2025-03-05 提交的版本。查看 最新版本

// ==UserScript==
// @name         字幕遮挡条
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  毛玻璃效果的字幕遮挡条,如果你看美剧英剧且不想看中文字幕的话,且快捷键V键可以快速启动
// @author       Cup Noodle
// @license MIT
// @match        *://*/*
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    GM_addStyle(`
    #bilibili-overlay-btn {
        position: fixed !important;
        right: 20px !important;
        bottom: 20px !important;
        z-index: 9999 !important;
        padding: 8px 12px !important;
        background-color: rgba(255,255,255,0.9) !important;
        border: 1px solid #ddd !important;
        border-radius: 4px !important;
        cursor: pointer !important;
        font-size: 14px !important;

        transition: left 0.2s, top 0.2s;
    }
    `);


    const button = document.createElement('div');
    button.id = 'bilibili-overlay-btn';
    button.textContent = '◼️ 字幕遮挡层';
    document.body.appendChild(button);

    const shortcutTip = document.createElement('div');
    shortcutTip.id = 'shortcut-tip';
    shortcutTip.textContent = '按 V 键';
    document.body.appendChild(shortcutTip);

    const overlay = document.createElement('div');
    overlay.style.position = 'fixed';

    const savedPosition = localStorage.getItem('overlayPosition');
    if (savedPosition) {
        const { top, left, width, height } = JSON.parse(savedPosition);
        overlay.style.top = top;
        overlay.style.left = left;
        overlay.style.width = width;
        overlay.style.height = height;
    } else {
        overlay.style.top = '200px';
        overlay.style.left = '200px';
        overlay.style.width = '900px';
        overlay.style.height = '45px';
    }
    overlay.style.backgroundColor = 'white';
    overlay.style.zIndex = '999999999999';
    overlay.style.cursor = 'default';
    overlay.style.display = 'none';
    overlay.style.borderRadius = '10px';
    overlay.style.background = 'rgba(255,255,255,0.1)';
    overlay.style.backdropFilter = 'blur(10px)';
    overlay.style.webkitBackdropFilter = 'blur(10px)';

    document.body.appendChild(overlay);

    let isDragging = false;
    let dragStartX, dragStartY;

    overlay.addEventListener('mousedown', function (e) {
        const rect = overlay.getBoundingClientRect();
        const isEdge = (
            e.clientX >= rect.right - 10 &&
            e.clientY >= rect.bottom - 10
        );

        if (!isEdge) {
            isDragging = true;
            dragStartX = e.clientX - parseInt(overlay.style.left, 10);
            dragStartY = e.clientY - parseInt(overlay.style.top, 10);
            document.body.style.cursor = 'move';
        }
    });

    document.addEventListener('mousemove', function (e) {
        if (isDragging) {
            overlay.style.left = (e.clientX - dragStartX) + 'px';
            overlay.style.top = (e.clientY - dragStartY) + 'px';
        }
    });

    document.addEventListener('mouseup', function () {
        if (isDragging) {
            isDragging = false;
            document.body.style.cursor = 'default';
            localStorage.setItem('overlayPosition', JSON.stringify({
                top: overlay.style.top,
                left: overlay.style.left,
                width: overlay.style.width,
                height: overlay.style.height
            }));
        }
    });

    function addResizableEffect(element) {
        const minWidth = 100;
        const minHeight = 10;

        element.onmousemove = function (e) {
            const rect = element.getBoundingClientRect();
            if (e.clientX > rect.left + rect.width - 10 || rect.left + 10 > e.clientX) {
                element.style.cursor = 'w-resize';
            } else if (e.clientY > rect.top + rect.height - 10) {
                element.style.cursor = 's-resize';
            } else if (e.clientY > rect.top && e.clientY < rect.top + 10) {
                element.style.cursor = 'n-resize';
            } else {
                element.style.cursor = 'default';
            }
        };

        element.onmousedown = (e) => {
            const clientX = e.clientX;
            const clientY = e.clientY;
            const elW = element.clientWidth;
            const elH = element.clientHeight;
            const EloffsetLeft = element.offsetLeft;
            const EloffsetTop = element.offsetTop;
            element.style.userSelect = 'none';

            const isTopResize = clientY > EloffsetTop && clientY < EloffsetTop + 10;

            document.onmousemove = function (e) {
                e.preventDefault();

                if (clientX > EloffsetLeft && clientX < EloffsetLeft + 10) {
                    const newWidth = elW - (e.clientX - clientX);
                    if (newWidth >= minWidth) {
                        element.style.width = newWidth + 'px';
                        element.style.left = EloffsetLeft + (e.clientX - clientX) + 'px';
                    }
                }
                if (clientX > EloffsetLeft + elW - 10 && clientX < EloffsetLeft + elW) {
                    const newWidth = elW + (e.clientX - clientX);
                    if (newWidth >= minWidth) {
                        element.style.width = newWidth + 'px';
                    }
                }
                if (clientY > EloffsetTop + elH - 10 && clientY < EloffsetTop + elH) {
                    const newHeight = elH + (e.clientY - clientY);
                    if (newHeight >= minHeight) {
                        element.style.height = newHeight + 'px';
                    }
                }
                if (isTopResize) {
                    const newHeight = elH - (e.clientY - clientY);
                    if (newHeight >= minHeight) {
                        element.style.height = newHeight + 'px';
                        element.style.top = EloffsetTop + (e.clientY - clientY) + 'px';
                    }
                }
            };

            document.onmouseup = function (e) {
                document.onmousemove = null;
                document.onmouseup = null;
                localStorage.setItem('overlayPosition', JSON.stringify({
                    top: overlay.style.top,
                    left: overlay.style.left,
                    width: overlay.style.width,
                    height: overlay.style.height
                }));
            };
        };
    }

    addResizableEffect(overlay);

    function applyStyles() {
        overlay.style.backdropFilter = `blur(10px)`;
        overlay.style.background = 'rgba(255,255,255,0.1)';
    }

    function toggleOverlay() {
        overlay.style.display = overlay.style.display === 'none' ? '' : 'none';
        button.textContent = overlay.style.display === '' ? '隐藏遮挡层' : '◼️ 字幕遮挡层';
        applyStyles();
    }

    button.addEventListener('click', toggleOverlay);
    shortcutTip.addEventListener('click', toggleOverlay);

    document.addEventListener('keydown', function (e) {
        if (e.key === 'v' || e.key === 'V') {
            toggleOverlay();
        }
    });


    function requestFullscreen(element) {
        if (element.requestFullscreen) {
            element.requestFullscreen();
        } else if (element.webkitRequestFullscreen) {
            element.webkitRequestFullscreen();
        } else if (element.mozRequestFullScreen) {
            element.mozRequestFullScreen();
        } else if (element.msRequestFullscreen) {
            element.msRequestFullscreen();
        }
    }

    function exitFullscreen() {
        if (document.exitFullscreen) {
            document.exitFullscreen();
        } else if (document.webkitExitFullscreen) {
            document.webkitExitFullscreen();
        } else if (document.mozCancelFullScreen) {
            document.mozCancelFullScreen();
        } else if (document.msExitFullscreen) {
            document.msExitFullscreen();
        }
    }

    const container = document.querySelector('.container');
    if (container) {
        const video = container.querySelector('video');
        if (video) {
            const fullscreenButton = video.parentNode.querySelector('.vjs-fullscreen-control');
            if (fullscreenButton) {
                fullscreenButton.addEventListener('click', function (e) {
                    e.preventDefault();
                    if (document.fullscreenElement === container) {
                        exitFullscreen();
                    } else {
                        requestFullscreen(container);
                    }
                });
            }
        }
    }
    document.addEventListener('fullscreenchange', function () {
        if (document.fullscreenElement) {
            button.style.display = 'none';
            shortcutTip.style.display = 'none';
            overlay.style.zIndex = '999999999999';
            const container = document.fullscreenElement || document.body;
            container.appendChild(overlay);
        } else {
            button.style.display = 'block';
            shortcutTip.style.display = 'block';
        }
    });

    const observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                const videoWrapper = document.querySelector('.bpx-player-container');
                if (videoWrapper && videoWrapper.classList.contains('bpx-player-container-web-fullscreen')) {
                    button.style.display = 'none';
                    shortcutTip.style.display = 'none';
                    overlay.style.zIndex = '999999999999';
                } else {
                    button.style.display = 'block';
                    shortcutTip.style.display = 'block';
                }
            }
        }
    });

    const videoWrapper = document.querySelector('.bpx-player-container');
    if (videoWrapper) {
        observer.observe(videoWrapper, { attributes: true, attributeFilter: ['class'] });
    }

})();