BiliBili一键关灯

点击按钮可使视频实现一键关灯模式

// ==UserScript==
// @name         BiliBili一键关灯
// @version      0.2.3
// @description  点击按钮可使视频实现一键关灯模式
// @author       GSK
// @include      *://*.bilibili.com/*
// @ico          https://www.bilibili.com/favicon.ico?v=1
// @grant    GM_setValue
// @grant    GM_getValue
// @license      MIT License
// @namespace https://greasyfork.org/users/1321187
// ==/UserScript==


(function() {

    'use strict';


    // // 键盘操作
    // document.onkeydown = hotkey;
    // function hotkey() {
    //     // 接收指令
    //     var keycode = window.event.keyCode;
    //     // 判断是否与目标码相同
    //     // 按键-:视频关灯
    //     if (keycode == 189) {
    //         // 通过标签拿资源
    //         var inputLight = document.querySelector('[aria-label="关灯模式"]');
    //         // 元素存在对其进行操作
    //         inputLight.click();

    //         // 关灯or开灯
    //         // document.getElementsByClassName("bui-checkbox-input")[3].click();
    //     }

    //     // 按键:番剧关灯
    //     //if (a == 83) {
    //     //    // 关灯or开灯
    //     //    document.getElementsByClassName("bui-checkbox-input")[1].click();
    //     //}

    //     // 按键=:删除头部
    //     if (keycode == 187) {
    //         // 获取div
    //         var div = document.getElementsByClassName("bili-header__bar")[0];
    //         // 删除div
    //         div.parentNode.removeChild(div);

    //     }
    // }




    // 声明所有需要共享的变量
    let deletedHeader = null;
        // 声明控制面板变量,初始为null
    let panel = null; // 用于存储控制面板的DOM元素

    // 1. 顶栏操作函数 ========================================

    /**
     * 切换顶栏显示状态的函数
     * 根据当前状态自动判断是隐藏还是显示顶栏
     */
    const toggleHeader = function () {
        // 如果deletedHeader存在,表示顶栏已被隐藏,需要恢复
        if (deletedHeader) {
            restoreHeader();
        }
        // 否则表示顶栏当前显示,需要隐藏
        else {
            hideHeader();
        }
    };

    /**
     * 隐藏顶栏的函数
     * 1. 查找顶栏元素
     * 2. 备份顶栏信息
     * 3. 从DOM中移除顶栏
     * 4. 更新按钮状态
     * 5. 保存状态到存储
     */
    const hideHeader = function () {
        // 查找顶栏元素
        const header = document.querySelector(".bili-header__bar");

        // 如果找到顶栏元素
        if (header) {
            // 备份顶栏信息到deletedHeader对象
            deletedHeader = {
                element: header, // 顶栏元素本身
                parent: header.parentNode, // 顶栏的父元素
                nextSibling: header.nextElementSibling, // 顶栏的下一个兄弟元素
                isHidden: true// 标记为已隐藏
            };

            // 从DOM中移除顶栏元素
            header.remove();

            // 更新控制面板按钮状态为"已隐藏"
            updateHeaderButton(true);

            // 将隐藏状态保存到GM存储
            GM_setValue('headerState', { isHidden: true });
        }
    };

    /**
     * 恢复顶栏的函数
     * 1. 检查是否有备份的顶栏
     * 2. 根据备份信息将顶栏恢复到原位置
     * 3. 更新按钮状态
     * 4. 清除备份
     * 5. 保存状态到存储
     */
    const restoreHeader = function () {
        // 检查是否有备份的顶栏
        if (deletedHeader) {
            // 如果原位置有下一个兄弟节点
            if (deletedHeader.nextSibling) {
                // 在兄弟节点前插入顶栏(恢复到原位置)
                deletedHeader.parent.insertBefore(
                    deletedHeader.element,
                    deletedHeader.nextSibling
                );
            }
            // 如果没有兄弟节点
            else {
                // 将顶栏追加到父元素末尾
                deletedHeader.parent.appendChild(deletedHeader.element);
            }

            // 更新控制面板按钮状态为"已显示"
            updateHeaderButton(false);

            // 清除备份的顶栏信息
            deletedHeader = null;

            // 将显示状态保存到GM存储
            GM_setValue('headerState', { isHidden: false });
        }
    };

    // 2. 更新按钮状态 ========================================

    /**
     * 更新控制面板中顶栏按钮状态的函数
     * @param {boolean} isHidden - 当前顶栏是否处于隐藏状态
     */
    const updateHeaderButton = function (isHidden) {
        // 获取顶栏切换按钮元素
        const headerBtn = document.querySelector('#bili-toggle-header');

        // 如果找到按钮元素
        if (headerBtn) {
            // 根据状态设置按钮内容和图标
            headerBtn.innerHTML = isHidden ?
                // 隐藏状态下的按钮内容
                `<svg viewBox="0 0 24 24"><path d="M19 11H5c-.55 0-1 .45-1 1s.45 1 1 1h14c.55 0 1-.45 1-1s-.45-1-1-1z"></path></svg>
             显示顶栏` :
                // 显示状态下的按钮内容
                `<svg viewBox="0 0 24 24"><path d="M19 13H5c-.55 0-1-.45-1-1s.45-1 1-1h14c.55 0 1 .45 1 1s-.45 1-1 1z"></path></svg>
             隐藏顶栏`;

            // 切换按钮的激活状态类
            headerBtn.classList.toggle('btn-active', isHidden);
        }
    };


    // 监听键盘按下事件
    document.onkeydown = function(event) {
        // 如果当前焦点在输入框内,则不执行快捷键操作
        if (document.activeElement.tagName === 'INPUT') return;

        // 根据按下的不同按键执行不同操作
        switch(event.key) {
                // 处理"-"键:开关关灯模式
            case '-': {
                // 查找关灯模式按钮
                const lightSwitch = document.querySelector('[aria-label="关灯模式"]');
                // 如果找到按钮,则模拟点击
                if (lightSwitch) lightSwitch.click();
                break; // 跳出switch语句
            }

                // 处理"="键:删除顶部导航栏
            case '=': {
                // 查找顶部导航栏元素
                //const header = document.querySelector(".bili-header__bar");
                //if (header) {
                //    // 备份元素及其位置信息
                //    deletedHeader = {
                //        element: header,// 元素本身
                //        parent: header.parentNode,// 父元素
                //        nextSibling: header.nextElementSibling // 下一个兄弟元素
                //    };
                //    // 从DOM中移除元素
                //    header.remove();
                //}
                toggleHeader();
                break;
            }

                // 处理"'"键:恢复顶部导航栏
            case "'": {
                // 检查是否有备份的头部元素
                if (deletedHeader) {
                    // 如果原位置有下一个兄弟节点
                    if (deletedHeader.nextSibling) {
                        // 在兄弟节点前插入
                        // 这是一个方法,避免方法排版混淆
                        // 提供原始方法格式deletedHeader.parent.insertBefore(deletedHeader.element,deletedHeader.nextSibling);
                        // 方法可以翻译为:parent.insertBefore(要插入的元素, 参考节点);
                        deletedHeader.parent.insertBefore(
                            deletedHeader.element,
                            deletedHeader.nextSibling
                        );
                    } else {
                        // 否则追加到父元素末尾
                        deletedHeader.parent.appendChild(deletedHeader.element);
                    }
                    // 恢复完成后清空备份
                    deletedHeader = null;
                }
                break;
            }
        }
    };


    //if(event.button == 0){
    //      //通过鼠标左键获取当下所指标签
    //    var clickedElement1 = event.target;
    //}


    // 鼠标操作
    document.onmousedown = function(event) {

        // 通过标签拿到关灯模式资源
        var inputLight = document.querySelector('[aria-label="关灯模式"]');
        // 通过标签拿到收藏模式按钮资源
        var Collect = document.querySelector('[title="收藏(E)"]');
        // 通过标签拿到收藏模式下的关闭按钮资源
        var Close = document.querySelector('[class="close"]');
        // 通过标签拿到收藏模式下的确定按钮资源
        var Enter = document.querySelector('[class="btn submit-move"]');

        // var event = event || window.event//兼容ie低版本的

        // 鼠标侧键4:前进按键(关灯操作,包括开闭)
        if(event.button == 4) {
            // 元素存在对其进行操作
            inputLight.click();
        }

        // 鼠标侧键3:后退按键(快捷键:收藏操作,包括选择性开闭)
        if(event.button == 3) {
            // 判断收藏页面确定按键元素是否存在
            if(Enter === null || Enter === undefined){
                // 确定按钮元素不存在进而判断关闭按钮元素是否存在
                if(Close === null || Close === undefined){
                    // 关闭按钮元素不存在对其进行收藏按钮操作
                    Collect.click();
                }else{
                    // 关闭元素存在对其进行点击操作
                    Close.click();
                }
            }else{
                // 确定按钮元素存在而进行点击确认操作
                Enter.click();
            }


        }

        // 鼠标侧键4:前进按键
        // if(event.button == 4) {
        //     // 获取head-div资源
        //     var div = document.getElementsByClassName("bili-header__bar")[0];
        //     // 判断head-div是否为空或者未定义
        //     // 或条件判断,二者满足其一为true,则为false
        //     if(div === null || div === undefined){
        //         // 满足条件true,执行下面代码
        //         //获取当下鼠标点击处标签
        //         var clickedElement = event.target;
        //获取当下鼠标点击处标签,然后直接删除(第二种实现方法)
        //         event.target.remove();
        //         //console.log('您当前获得的标签是: ' + clickedElement.tagName);
        //         //删除因点击所获的标签
        //         clickedElement.parentNode.removeChild(clickedElement);
        //     }else{
        //         // 不足条件false,执下面代码
        //         // 直接删除head-div资源
        //         div.parentNode.removeChild(div);
        //     }
        // }

    }

    // Your code here...


    // // 创建控制面板
    // const createControlPanel = function() {
    //     // 创建样式
    //     const style = document.createElement('style');
    //     style.textContent = `
    //         .bili-custom-panel {
    //             position: fixed;
    //             top: 100px;
    //             left: 20px;
    //             width: 200px;
    //             min-width: 180px;
    //             max-width: 300px;
    //             min-height: 180px;
    //             background: rgba(0,0,0,0.8);
    //             border-radius: 8px;
    //             padding: 12px;
    //             color: white;
    //             z-index: 9999;
    //             cursor: move;
    //             backdrop-filter: blur(8px);
    //             border: 1px solid rgba(255,255,255,0.3);
    //             box-shadow: 0 6px 16px rgba(0,0,0,0.4);
    //             resize: none;
    //             overflow: hidden;
    //             font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    //         }
    //         .bili-custom-panel h3 {
    //             margin: 0 0 12px 0;
    //             padding-bottom: 8px;
    //             border-bottom: 1px solid rgba(255,255,255,0.3);
    //             font-size: 15px;
    //             user-select: none;
    //             font-weight: 500;
    //         }
    //         .bili-custom-btn {
    //             display: flex;
    //             align-items: center;
    //             width: 100%;
    //             padding: 8px 12px;
    //             margin: 6px 0;
    //             background: rgba(255,255,255,0.12);
    //             border: none;
    //             border-radius: 6px;
    //             color: white;
    //             text-align: left;
    //             cursor: pointer;
    //             transition: all 0.2s;
    //             font-size: 13px;
    //         }
    //         .bili-custom-btn:hover {
    //             background: rgba(255,255,255,0.2);
    //             transform: translateY(-1px);
    //         }
    //         .bili-custom-btn:active {
    //             transform: translateY(0);
    //         }
    //         .bili-custom-btn svg {
    //             flex-shrink: 0;
    //             margin-right: 8px;
    //             width: 16px;
    //             height: 16px;
    //             fill: currentColor;
    //         }
    //         .panel-resize-handle {
    //             position: absolute;
    //             background: transparent;
    //             z-index: 10;
    //         }
    //         .panel-resize-handle-e {
    //             cursor: e-resize;
    //             width: 10px;
    //             height: 100%;
    //             right: 0;
    //             top: 0;
    //         }
    //         .panel-resize-handle-s {
    //             cursor: s-resize;
    //             height: 10px;
    //             width: 100%;
    //             bottom: 0;
    //             left: 0;
    //         }
    //         .panel-resize-handle-se {
    //             cursor: se-resize;
    //             width: 16px;
    //             height: 16px;
    //             right: 0;
    //             bottom: 0;
    //         }
    //         .btn-active {
    //             background: rgba(255,255,255,0.25) !important;
    //             color: #fff;
    //         }
    //     `;
    //     document.head.appendChild(style);

    //     // 创建面板 - 使用已声明的panel变量
    //     panel = document.createElement('div');
    //     panel.className = 'bili-custom-panel';
    //     panel.innerHTML = `
    //         <h3>B站增强控制</h3>
    //         <button class="bili-custom-btn" id="bili-toggle-light">
    //             <svg viewBox="0 0 24 24"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1z"></path></svg>
    //             开关灯模式
    //         </button>
    //         <button class="bili-custom-btn" id="bili-toggle-header">
    //             <svg viewBox="0 0 24 24"><path d="M19 13H5c-.55 0-1-.45-1-1s.45-1 1-1h14c.55 0 1 .45 1 1s-.45 1-1 1z"></path></svg>
    //             隐藏顶栏
    //         </button>
    //         <button class="bili-custom-btn" id="bili-fullscreen">
    //             <svg viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></svg>
    //             全屏播放器
    //         </button>
    //         <div class="panel-resize-handle panel-resize-handle-e"></div>
    //         <div class="panel-resize-handle panel-resize-handle-s"></div>
    //         <div class="panel-resize-handle panel-resize-handle-se"></div>
    //     `;
    //     document.body.appendChild(panel);

    //     // 拖拽功能实现
    //     let isDragging = false;
    //     let isResizing = false;
    //     let resizeDirection = '';
    //     let offsetX, offsetY;
    //     let startX, startY, startWidth, startHeight;

    //     // 面板拖拽
    //     panel.addEventListener('mousedown', (e) => {
    //         if (e.target.classList.contains('panel-resize-handle')) {
    //             isResizing = true;
    //             isDragging = false;
    //             resizeDirection = e.target.classList.contains('panel-resize-handle-e') ? 'e' :
    //             e.target.classList.contains('panel-resize-handle-s') ? 's' : 'se';
    //             startX = e.clientX;
    //             startY = e.clientY;
    //             startWidth = parseInt(document.defaultView.getComputedStyle(panel).width, 10);
    //             startHeight = parseInt(document.defaultView.getComputedStyle(panel).height, 10);
    //             e.preventDefault();
    //             return;
    //         }

    //         if (e.target.tagName === 'BUTTON') return;

    //         isDragging = true;
    //         isResizing = false;
    //         offsetX = e.clientX - panel.getBoundingClientRect().left;
    //         offsetY = e.clientY - panel.getBoundingClientRect().top;
    //         panel.style.cursor = 'grabbing';
    //         e.preventDefault();
    //     });

    //     document.addEventListener('mousemove', (e) => {
    //         if (isResizing) {
    //             const width = startWidth + (resizeDirection.includes('e') ? (e.clientX - startX) : 0);
    //             const height = startHeight + (resizeDirection.includes('s') ? (e.clientY - startY) : 0);

    //             if (width > 150 && width < 500) {
    //                 panel.style.width = width + 'px';
    //             }
    //             if (height > 150 && height < 500) {
    //                 panel.style.height = height + 'px';
    //             }
    //         } else if (isDragging) {
    //             panel.style.left = (e.clientX - offsetX) + 'px';
    //             panel.style.top = (e.clientY - offsetY) + 'px';
    //         }
    //     });

    //     document.addEventListener('mouseup', () => {
    //         if (isDragging || isResizing) {
    //             // 保存位置和大小
    //             GM_setValue('panelSettings', {
    //                 left: panel.style.left,
    //                 top: panel.style.top,
    //                 width: panel.style.width,
    //                 height: panel.style.height
    //             });
    //         }
    //         isDragging = false;
    //         isResizing = false;
    //         panel.style.cursor = 'move';
    //     });

    //     // 恢复位置和大小
    //     const savedSettings = GM_getValue('panelSettings');
    //     if (savedSettings) {
    //         panel.style.left = savedSettings.left || '20px';
    //         panel.style.top = savedSettings.top || '100px';
    //         if (savedSettings.width) panel.style.width = savedSettings.width;
    //         if (savedSettings.height) panel.style.height = savedSettings.height;
    //     }

    //     // 初始化按钮状态
    //     const headerState = GM_getValue('headerState');
    //     if (headerState && headerState.isHidden) {
    //         updateHeaderButton(true);
    //     }

    //     // 按钮事件监听
    //     panel.querySelector('#bili-toggle-light').addEventListener('click', () => {
    //         const btn = document.querySelector('[aria-label="关灯模式"]');
    //         if (btn) btn.click();
    //     });

    //     panel.querySelector('#bili-toggle-header').addEventListener('click', toggleHeader);

    //     panel.querySelector('#bili-fullscreen').addEventListener('click', () => {
    //         const player = document.querySelector('.bpx-player-container');
    //         if (player) {
    //             if (player.requestFullscreen) player.requestFullscreen();
    //             else if (player.webkitRequestFullscreen) player.webkitRequestFullscreen();
    //         }
    //     });
    // };

    // // 初始化
    // if (document.readyState === 'complete') {
    //     createControlPanel();
    // } else {
    //     window.addEventListener('load', createControlPanel);
    // }
    // Your code here...

})();