Greasy Fork

Greasy Fork is available in English.

bilibili关灯

bilibili关灯(把被新版B站藏起来的关灯按钮揪出来,在关闭弹幕按钮左边,还可以用快捷键,默认'A')

当前为 2021-07-11 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         bilibili关灯
// @namespace    hhh2000
// @version      0.7.9
// @description  bilibili关灯(把被新版B站藏起来的关灯按钮揪出来,在关闭弹幕按钮左边,还可以用快捷键,默认'A')
// @author       hhh2000
// @include      *://*.bilibili.com/video/*
// @include      *://*.bilibili.tv/video/*
// @include      *://*.bilibili.com/bangumi/*
// @include      *://*.bilibili.tv/bangumi/*
// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
// @run-at       document-end
// @grant        none
// ==/UserScript==

'use strict';
hhh_lightoff_main = {
    init() {
        var //
            fps,
            h5Player;
        var //切换番剧和一般视频class
            bb = {},
            bb_type = '',
            bb_config = {
                bb_class_data: {
                    'player':{'bili':'.player', 'bpx':'.bpx-player'}, //main player

                    'webFullScreen':{'bili':'.bilibili-player-video-web-fullscreen'}, //网页全屏
                    'wideScreen':{'bili':'.bilibili-player-video-btn-widescreen'}, //宽屏

                    'danmukuTopClose':{'bili':'.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_top_close]'}, //顶部弹幕
                    'danmukuTop':{'bili':'.bilibili-player-block-filter-type[ftype=top]'}, //顶部弹幕
                    'danmukuBottomClose':{'bili':'.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_bottom_close]'}, //底部弹幕
                    'danmukuBottom':{'bili':'.bilibili-player-block-filter-type[ftype=bottom]'}, //底部弹幕

                    'thumbTooltip':{'bili':'.bui-thumb-tooltip'}, //弹幕透明度读数
                    'settingOpacity':{'bili':'.bilibili-player-setting-opacity'}, //弹幕透明度
                    'settingArea':{'bili':'.bilibili-player-setting-area'}, //显示区域
                    'volumeHint':{'bili':'.bilibili-player-volumeHint'}, //音量显示
                    'volumeHintText':{'bili':'.bilibili-player-volumeHint-text'}, //音量显示百分比读数
                    'volumeHintIcon':{'bili':'.bilibili-player-volumeHint-icon'}, //音量显示图标

                    'switchBody':{'all':'.bui-switch-body'}, //系统关灯css设置
                    'switchDot':{'all':'.bui-switch-dot'}, //系统弹幕设置按钮wrap进度条拖动点
                    'switchInput':{'all':'.bui-switch-input'}, //弹幕设置switch按钮
                    'danmakuRoot':{'bili':'.bilibili-player-video-danmaku-root', 'bpx':'.bpx-player-dm-root'}, //系统弹幕设置条
                    'danmakuSwitch':{'bili':'.bilibili-player-video-danmaku-switch', 'bpx':'.bpx-player-dm-switch'}, //关闭弹幕按钮
                    'danmakuSetting':{'bili':'.bilibili-player-video-danmaku-setting'}, //系统弹幕设置按钮
                    'danmakuSettingWrap':{'bili':'.bilibili-player-video-danmaku-setting-wrap'}, //系统弹幕设置按钮wrap
                    'videoWrap':{'bili':'.bilibili-player-video-wrap', 'bpx':'.bpx-player-video-area'}, //播放wrap
                    'videoContextMenu':{'bili':'.bilibili-player-video-wrap', 'bpx':'.bpx-player-video-perch'}, //播放contextmenu
                    'video':{'bili':'.bilibili-player-video', 'bpx':'.bpx-player-video-wrap'}, //播放
                    'videoTopMask':{'bili':'.bilibili-player-video-top-mask'}, //全屏时鼠标悬停时产生的顶端mask

                    'playVideo':{'bili':'.bilibili-player-video-btn'}, //系统设置
                    'playSetting':{'bili':'.bilibili-player-video-btn-setting'}, //系统播放设置
                    'playSettingWrap':{'bili':'.bilibili-player-video-btn-setting-wrap'}, //系统播放设置wrap
                    'playSettingAutoplay':{'bili':'.bilibili-player-video-btn-setting-left-autoplay'}, //自动播放
                    'playSettingRepeat':{'bili':'.bilibili-player-video-btn-setting-left-repeat'}, //洗脑循环
                    'playSettingLightoff':{'bili':'.bilibili-player-video-btn-setting-right-others-content-lightoff input', 'bpx':'.squirtle-single-setting-other-choice squirtle-lightoff'}, //关灯按钮
                    'bpxStateLightOff':{'bpx':'.bpx-state-light-off'}, //关灯bpx

                    'playerContextMenu':{'bili':'.bilibili-player-context-menu-container.black.bilibili-player-context-menu-origin', 'bpx':'.bpx-player-contextmenu.bpx-player-black.bpx-player-active'}, //右键菜单
                    'hotkeyPanel':{'bili':'.bilibili-player-hotkey-panel'}, //快捷键说明面板
                    'videoInfo':{'bili':'.bilibili-player-video-info', 'bpx':'.bpx-player-info'}, //视频统计信息
                    'videoInfoShow':{'bili':'.bilibili-player-video-info-container active', 'bpx':'.bpx-player-info-container'}, //视频统计信息面板显示

                },
                set_bb(bb_type) {
                    for(var k in this.bb_class_data){
                        var class_str = this.bb_class_data[k][bb_type]!==undefined? this.bb_class_data[k][bb_type]: this.bb_class_data[k]['all'];
                        bb[k] = class_str;
                        //console.log('--'+bb[k]);

                    }
                }
           };

        var //config
            ON = true,
            OFF = false,
            keycode = {
                'left': 37,
                'right': 39,
            }
            config = {
                //一些主要开关设置
                sets: {},
                getCheckboxSetting(key) {
                    return this.sets[key]['status'];
                },
                saveCheckboxSetting() {
                    for(var o in this){
                        if(o.indexOf('b_') === 0){
                            var op = this[o]['options'];
                            for(var k in op){
                                this.sets[k] = op[k];
                            }
                        }
                    }
                },
                b_playerCheckbox: {
                    options: {
                        lightOffWhenPlaying: { text: '播放时自动关灯', status: OFF },
                        lightOnWhenPause: { text: '暂停时自动开灯', status: OFF },
                        autoPlay: { text: '开启自动播放', status: OFF, fn: '', tips: '' },
                        repeat: { text: '开启洗脑循环', status: ON, tips: '' },
                        lightOff: { text: '自动关灯', status: OFF, tips: '' },
                        volumeControlWhenNonFullScreen: { text: '开启非全屏滚轮音量调节', status: ON, tips: '' },
                        volumeControlWhenPause: { text: '非全屏暂停时滚轮音量调节', status: ON, tips: '' },
                        danmuOpacityControl: { text: '开启滚轮弹幕透明度控制', status: ON, tips: '' }, //ctrl+滚轮
                        removeVideoTopMask: { text: '去掉顶部mask', status: ON, tips: '' },
                        //不显示有明显变化的提示,关灯、关弹幕等,因为对有些人来说这些操作变化明显可见,提示反而多余且遮挡屏幕
                        hotKeyHint: { text: '快捷键屏幕提示', status: ON, tips: '' },
                    },
                    btn: '设置'
                },
                //快捷键
                QDs: {}, //未使用
                getQD(key) {
                    return this.QDs[key];
                }, //未使用
                saveQD() {
                    for (let [key, { value, text }] of Object.entries(this.hotKeyMenu)) {
                        this.QDs[key] = {value: value, keyCode: value.charCodeAt(), text: text};
                    }
                }, //未使用
                hotKeyMenu: {  //只是右键菜单的数据,如需改动快捷键改run函数
                    'lightOff': { value: 'A', text: '关灯/开灯', },
                    'webFullscreen': { value: 'W', text: '网页全屏', },
                    'widescreen': { value: 'Q', text: '宽屏模式', },
                    'danmu': { value: 'D', text: '弹幕/关闭弹幕', },
                    'danmuTop': { value: 'T', text: '顶部弹幕', },
                    'danmuBottom': { value: 'B', text: '底部弹幕', },
                    'videoRepeat': { value: 'R', text: '洗脑循环', },
                    'subDanmuOpacity': { value: 'Z', text: '减弹幕透明度', },
                    'addDanmuOpacity': { value: 'C', text: '加弹幕透明度', },
                    'quarterArea': { value: '1', text: '1/4屏', },
                    'halfArea': { value: '2', text: '半屏', },
                    'threeQuarterArea': { value: '3', text: '3/4屏', },
                    'nonOverArea': { value: '4', text: '不重叠', },
                    'fullArea': { value: '5', text: '不限', },
                    'wheelDanmuOpacity': { value: 'Ctrl + 滚轮', text: '增减弹幕透明度', },
                },
            };

        function abc(e) {console.log(e)}
        function waitForNode(nodeSelector, callback, times) {
            if(times < 0) return;
            var node = nodeSelector();
            if (node) {
                callback(node);
            } else {
                times-=1;
                setTimeout(function() { waitForNode(nodeSelector, callback, times); }, 100);
            }
        }
        function waitForTrue(ifTrue, callback) {
            if (ifTrue()) {
                callback();
            } else {
                setTimeout(function() { waitForTrue(ifTrue, callback); }, 100);
            }
        }
        function is_lightoff() {
            if (bb_type === 'bili') { return !player.getPlayerState().lightOn }
            else if(bb_type === 'bpx') { return $(`${bb['player']}${bb['bpxStateLightOff']}`).length === 1 }
            else return null;
        }
        function lightoff() {
            if (bb_type === 'bili') { $(bb['playSettingLightoff']).click() }
            else if(bb_type === 'bpx') {
                if(is_lightoff() === true) {
                    $('.bpx-player').attr('class', 'bpx-player');
                    $('.squirtle-single-setting-other-choice.squirtle-lightoff').attr('class', 'squirtle-single-setting-other-choice squirtle-lightoff');
                } else {
                    $('.bpx-player').attr('class', 'bpx-player bpx-state-light-off');
                    $('.squirtle-single-setting-other-choice.squirtle-lightoff').attr('class', 'squirtle-single-setting-other-choice squirtle-lightoff active');
                }
            }
        }
        //squirtle-single-setting-other-choice squirtle-lightoff active //关灯按钮
        //bpx-player bpx-state-light-off //实际关灯
        //bpxStateLightoff
        //关灯按钮样式
        function lightoff_btn_css() {
            var body_brgb = 'rgb(160, 130, 110)';
            var dot_crgb = 'rgb(230, 200, 180)';
            var dot_brgb = 'rgb(50, 50, 50)';
            var dark_rgb = 'rgb(77, 77, 77)';
            if ($('#hhh_lightoff '+bb['switchInput'])[0].checked === false) {  //关灯
                $('#hhh_lightoff '+bb['switchBody']+':first').css('background-color', dark_rgb);
                $('#hhh_lightoff '+bb['switchBody']+':first>'+bb['switchDot']).css('color', dark_rgb);
            }
            else {
                $('#hhh_lightoff '+bb['switchBody']+':first').css('background-color', body_brgb);
                $('#hhh_lightoff '+bb['switchBody']+':first>'+bb['switchDot']).css({'color': dot_crgb, 'background-color': dot_brgb});
            }
        }
        //关灯按钮
        function lightoff_btn() {
            lightoff();
            if(is_lightoff() === $('#hhh_lightoff '+bb['switchInput'])[0].checked) {  //checked==true开灯 false关灯
                $('#hhh_lightoff '+bb['switchInput'])[0].checked = !$('#hhh_lightoff '+bb['switchInput'])[0].checked;
            }
            lightoff_btn_css();
        }

        //显示提示
        function showHint(parent, selector_str, text){
            $(bb['volumeHint']).css('display', 'none');  //隐藏所有提示,避免重叠
            $(`${selector_str}>${bb['volumeHintText']}`).text(text);  //百分比显示
            var Hint = $(selector_str);  //显示及渐隐效果(抄bilibili^^)
            clearTimeout(parent.showHintTimer),
                Hint.stop().css("opacity", 1).show(),
                parent.showHintTimer = window.setTimeout((function() {
                Hint.animate({
                    opacity: 0
                }, 300, (function() {
                    $(this).hide()
                }
                ))
            }
            ), 1e3)
        }
        //非全屏滚轮音量调节 0~1 (b站默认滚轮操作某些情况会失效,一并处理全屏情况)
        //两个参数指定屏幕范围(按百分比),第三个参数表示滚动一下增加的音量百分比,参数四表示暂停时是否调解
        function wheel_volumeHint(screenLeft, screenRight, delta, isPauseVolume){
            //div(抄bilibili^^)
            // ** video-state-volume-max video-state-volume-min
            var volumeHint = `<div id=hhh_volumeHint class="${bb['volumeHint'].substr(1)}" style="opacity: 0; display: none;">
                                <span class="${bb['volumeHintIcon'].substr(1)}">
                                  <i class="bilibili-player-iconfont bilibili-player-iconfont-volume icon-24soundsmall"></i>
                                  <i class="bilibili-player-iconfont bilibili-player-iconfont-volume-max icon-24soundlarge"></i>
                                  <i class="bilibili-player-iconfont bilibili-player-iconfont-volume-min icon-24soundoff"></i>
                                </span>
                                <span class="${bb['volumeHintText'].substr(1)}">57%</span>
                              </div>`;
            if($('#hhh_volumeHint').length === 0) $(bb['videoWrap']).append(volumeHint);

            //add wheelevent
            $(bb['videoWrap']).off('mousewheel.hhh_volumeHint');
            $(bb['videoWrap']).on('mousewheel.hhh_volumeHint', function(e){
                if(e.ctrlKey || e.altKey || e.shiftKey) return;
                //缺省屏幕百分比参数,默认0.3~0.7
                screenLeft = screenLeft<0?undefined:screenLeft>1?undefined:screenLeft;
                screenRight = screenRight<0?undefined:screenRight>1?undefined:screenRight;
                if(screenLeft === undefined || screenRight === undefined) { screenLeft = 0.3; screenRight = 0.7 }
                //缺省音量百分比,默认3
                delta = delta<1?3:delta>100?3:delta===undefined?3:delta;
                //非暂停 && 鼠标在屏幕指定位置时处理
                var pauseState = isPauseVolume || player.getState() !== 'PAUSED';
                var w = $(this).width();
                var e_in_Hint = w !== $(e.target).width();  //处理鼠标在提示上的情况
                var inLimit = e_in_Hint || (e.originalEvent.offsetX > w*screenLeft && e.originalEvent.offsetX < w*screenRight);
                if(player.isFullScreen() === true || (pauseState && inLimit)) {
                    e.preventDefault();  //阻止页面滚动
                    e.stopPropagation();  //阻止冒泡
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var volume = player.volume();
                    if(wheelDelta >= 120) {  //向上滚动,减少音量
                        player.volume(volume+(delta/100));
                    } else if(wheelDelta <= -120) {  //向下滚动,增大音量
                        player.volume(volume-(delta/100));
                    }

                    var vol = player.volume();
                    var $volumeHintIcon = $(`#hhh_volumeHint ${bb['volumeHintIcon']}`);
                    if(vol <= 0) $volumeHintIcon.attr('class', `${bb['volumeHintIcon'].substr(1)} video-state-volume-min`);
                    else if(vol >= 1) $volumeHintIcon.attr('class', `${bb['volumeHintIcon'].substr(1)} video-state-volume-max`);
                    else $volumeHintIcon.attr('class', bb['volumeHintIcon'].substr(1));

                    if(vol <= 0) showHint(this, '#hhh_volumeHint', '静音');
                    else showHint(this, '#hhh_volumeHint', Math.round(vol*100)+'%');
                }
            });
        }
        /*
         * 调节透明度
         * 利用系统mousedown事件
         * '正数': right,  '负数': left,  -100 ~ +100
         */
        function adjust_progress(selector_str, percent){
            var selector = document.querySelector(selector_str);
            var e1 = new MouseEvent('mousedown'); var e2 = new MouseEvent('mouseup');
            var tip_selector = document.querySelector(`${selector_str} ${bb['thumbTooltip']}`);

            function calc_bar_len(percent){
                var p = percent - 10;
                p = p<0? 0: p>90? 90: p;
                return p<=40? p*2.5: (p-40)*2 + 40*2.5;  //进度条对应百分比的系统算法
            }

            $(bb['danmakuSettingWrap']).css({"display":"block"});

            var selector_rect = selector.getClientRects();
            var curr_percent = Number(tip_selector.innerHTML.slice(0,-1));
            var clientX = selector_rect[0].left + calc_bar_len(curr_percent + percent);
            e1.initMouseEvent('mousedown',1,1,window,1,0,0,clientX,0,0,0,0,0,0,null);
            e2.initMouseEvent('mouseup'  ,1,1,window,1,0,0,clientX,0,0,0,0,0,0,null);
            selector.dispatchEvent(e1); selector.dispatchEvent(e2);

            $(bb['danmakuSettingWrap']).css({"display":"none"});

            $(bb['danmakuSetting']).mouseleave();  //激活设置,记忆进度条位置
            return tip_selector.innerHTML.slice(0,-1);
        }
        /*
         * 控制进度条
         * .bilibili-player-setting-opacity 透明度
         * .bilibili-player-setting-area 显示区域
         * .bilibili-player-setting-speedplus 弹幕速度 等
         * 利用系统mousedown事件
         * 0 ~ 100
         */
        function set_progress(selector_str, percent){
            var selector = document.querySelector(selector_str);
            var e1 = new MouseEvent('mousedown'); var e2 = new MouseEvent('mouseup');

            function calc_bar_len(percent){
                var p = percent - 10;
                p = p<0? 0: p>90? 90: p;
                return p<=40? p*2.5: (p-40)*2 + 40*2.5;  //进度条对应百分比的系统算法
            }

            $(bb['danmakuSettingWrap']).css({"display":"block"});

            var selector_rect = selector.getClientRects();
            var clientX = selector_rect[0].left + calc_bar_len(percent);
            e1.initMouseEvent('mousedown',1,1,window,1,0,0,clientX,0,0,0,0,0,0,null);
            e2.initMouseEvent('mouseup'  ,1,1,window,1,0,0,clientX,0,0,0,0,0,0,null);
            selector.dispatchEvent(e1); selector.dispatchEvent(e2);

            $(bb['danmakuSettingWrap']).css({"display":"none"});

            $(bb['danmakuSetting']).mouseleave();  //激活设置,记忆进度条位置
        }
        //滚轮调节弹幕透明度(ctrl),参数表示滚动一下增加的透明度百分比
        function wheel_opacity(delta){
            //add wheelevent
            $(bb['videoWrap']).off('mousewheel.hhh_opacity');
            $(bb['videoWrap']).on('mousewheel.hhh_opacity', function(e){
                if(e.ctrlKey === true) {
                    //缺省透明度百分比,默认5
                    delta = delta<1?5:delta>100?5:delta===undefined?5:delta;
                    e.preventDefault();  //阻止页面滚动
                    e.stopPropagation();  //阻止冒泡
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var opacity = -1;
                    if(wheelDelta >= 120) {  //向上滚动,增大透明度
                        opacity = adjust_progress(bb['settingOpacity'], delta);
                    } else if(wheelDelta <= -120) {  //向下滚动,减少透明度
                        opacity = adjust_progress(bb['settingOpacity'], -delta);
                    }
                    if(opacity >= 0) showHint(document, '#hhh_opacityHint', '透 '+opacity+'%');
                }
            });
        }
        //取得视频FPS(Frames Per Second)
        function get_video_fps() {
            var evt = new MouseEvent('contextmenu', { clientX:300, clientY:100 });
            $(bb['videoContextMenu'])[0].dispatchEvent(evt);
            var video_info_class = bb['videoInfo'].substr(1);
            var oV = $(bb['videoWrap'])[0];
            oV.addEventListener('DOMNodeInserted', function(e) {
                if(typeof e.target.className === 'string' && e.target.className.indexOf(`${bb['videoInfoShow'].substr(1)}`) !== -1) {
                    this.removeEventListener('DOMNodeInserted', arguments.callee);
                    var $videoinfo = $(e.target).attr('class', `${video_info_class}-container`);
                    fps = $videoinfo.find('.info-line[data-name="resolution"]>.info-data').text().split('@')[1];
                    fps = Number(fps);
                }
            })
            //模拟点击,激活热键菜单DOM
            $(`${bb['playerContextMenu']} a:contains("视频统计信息")`).click();
        }
        //TEST
        function get_video_fps_test() {
            var evt = new MouseEvent('contextmenu', { clientX:300, clientY:100 });
            $(bb['videoContextMenu'])[0].dispatchEvent(evt);

            //TEST
            $(`${bb['playerContextMenu']} li:contains("视频统计信息")`).click();
            return;

            var video_info_class = bb['videoInfo'].substr(1);
            var oV = $(bb['videoWrap'])[0];
            oV.addEventListener('DOMNodeInserted', function(e) {
                    console.log('className: '+e.target.className);
                if(typeof e.target.className === 'string' && e.target.className.indexOf(`${bb['videoInfoShow'].substr(1)}`) !== -1) {
                    console.log(e.target.className);
                    this.removeEventListener('DOMNodeInserted', arguments.callee);
                    var $videoinfo = $(e.target).attr('class', `${video_info_class}-container`);
                    fps = $videoinfo.find('.info-line[data-name="resolution"]>.info-data').text().split('@')[1];
                    fps = Number(fps);
                }
            })
            //模拟点击,激活热键菜单DOM
            $(`${bb['playerContextMenu']} a:contains("视频统计信息")`).click();
        }

        //添加右键菜单自定义快捷键说明
        function add_custom_hotkey_menu(custom_hotkey) {
            if($('#hhh_hotkey').length === 1) return;
            //模拟右键菜单消息,激活菜单DOM
            var evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
            $(bb['videoWrap'])[0].dispatchEvent(evt);
            //主class名,没有"."
            var hotkey_panel_class = bb['hotkeyPanel'].substr(1);
            //右键菜单弹出时添加项
            (function add_menu() {
                var oV = $(bb['playerContextMenu'])[0];
                oV.addEventListener('DOMSubtreeModified', function(e) {
                    if(typeof e.target.className === 'string' && e.target.className.indexOf(bb['playerContextMenu'].replace(/\./g, ' ').substr(1)) !== -1 && $(this).attr('id') === undefined) {
                        this.removeEventListener('DOMSubtreeModified', arguments.callee);
                        var $sys_hotkey = $(this).find('a:contains("快捷键说明")').parent();
                        var $hhh_hotkey = $sys_hotkey.clone(false, false).insertAfter($sys_hotkey).css('display', '').find('a').text('快捷键说明(bilibili关灯)');

                        $sys_hotkey.find('a').click(function(){
                            $('#sys_hotkey').clone(true,true).replaceAll($(`.${hotkey_panel_class}-container:last`)).attr({'id': '', 'class': `${hotkey_panel_class}-container`, 'style': ''});
                        });
                        $hhh_hotkey.click(function(){
                            $('#hhh_hotkey').clone(true,true).replaceAll($(`.${hotkey_panel_class}-container:last`)).attr({'id': '', 'class': `${hotkey_panel_class}-container`, 'style': ''});
                        });

                        add_menu();
                    }
                });
            })();
            //生成自定义快捷键说明页面
            (function add_custom_hotkey() {
                var oV = $(bb['videoWrap'])[0];
                oV.addEventListener('DOMNodeInserted', function(e) {
                    if(typeof e.target.className === 'string' && e.target.className.indexOf(`${hotkey_panel_class}-container active`) !== -1) {
                        this.removeEventListener('DOMNodeInserted', arguments.callee);
                        var $hotkey = $(e.target).attr('class', `${hotkey_panel_class}-container`);
                        $hotkey.clone().insertBefore($hotkey).attr({'class': '','id': 'sys_hotkey'}).css('display', 'none');
                        $hotkey.clone().insertBefore($hotkey).attr({'class': '','id': 'hhh_hotkey'}).css('display', 'none');

                        (function set_custom_hotkey($hotkey, hotkey) {
                            var $hotkey_panel = $hotkey.find(`.${hotkey_panel_class}:first`);
                            var $hotkey_item  = $hotkey.find(`.${hotkey_panel_class}-item:first`);
                            $hotkey_panel.empty();
                            for (let [key, { value, text }] of Object.entries(hotkey)) {
                                $hotkey_item.clone().appendTo($hotkey_panel);
                                var $hotkey_key = $hotkey_panel.find(`.${hotkey_panel_class}-key:last`);
                                $hotkey_key.text(value);
                                $hotkey_key.next().text(text);
                            }
                        })($('#hhh_hotkey'), custom_hotkey);

                    }
                });
            })();
            //模拟点击,激活热键菜单DOM
            $(`${bb['playerContextMenu']} a:contains("快捷键说明")`).click();
        }

        //主程序
        function run(){

            waitForNode(() => document.querySelector('video'),
                        (node) => {
                bb_type = $('.player').length===1? 'bili':$('.bpx-player').length===1? 'bpx': '';
                bb_config.set_bb(bb_type);
            }, 10000);

            waitForNode(() => document.querySelector(`${bb['danmakuSwitch']} ${bb['switchDot']}`),
                        (node) => {

                //保存设置信息 && 快捷键信息
                config.saveCheckboxSetting();

                //防止重复加载
                if ($('#hhh_lightoff').length === 1) return;

                //取得h5 video
                h5Player = $(`#bilibili-player ${bb['video']}>video`)[0];
                //取得视频fps
                get_video_fps();

                //插入关灯按钮
                $(`${bb['danmakuSwitch']}:first`).clone().prependTo(`${bb['danmakuRoot']}:first`)[0].id = 'hhh_lightoff';
                $(`#hhh_lightoff ${bb['switchDot']}`)[0].innerHTML = '灯';

                //点击关灯
                $(`#hhh_lightoff ${bb['switchInput']}:first`).click(function(){ lightoff_btn() });

                //TEST
                //lightoff_btn_css();
                //return;

                //键盘关灯等
                var opacity;
                var parent = document;
                var is_show_hint = config.getCheckboxSetting('hotKeyHint');
                $(document).off('keydown.hhh_lightoff');
                $(document).on('keydown.hhh_lightoff',function(e){
                    if(e.keyCode === 'A'.charCodeAt()){  //开关灯
                        is_show_hint && (is_lightoff() ? showHint(parent, '#hhh_wordsHint', '开灯') : showHint(parent, '#hhh_wordsHint', '关灯'));
                        lightoff_btn();
                    } else if(e.keyCode === 'W'.charCodeAt()) {  //网页全屏
                        $(bb['webFullScreen']).click();
                    } else if(e.keyCode === 'Q'.charCodeAt()) {  //宽屏模式
                        player.isFullScreen() ? $(bb['webFullScreen']).click() : $(bb['wideScreen']).click();
                    } else if(e.keyCode === 'D'.charCodeAt()) {  //开关弹幕
                        $(bb['danmakuSwitch']+'>'+bb['switchInput']+':last').click();
                        is_show_hint && (player.getPlayerState().danmaku.show === true ? showHint(parent, '#hhh_wordsHint', '开弹幕') : showHint(parent, '#hhh_wordsHint', '关弹幕'));
                    } else if(e.keyCode === 'T'.charCodeAt()) {  //开关顶部弹幕
                        //bpx-player-block-filter-type bpx-player-block-typeTop bpx-player-active
                        $(bb['danmukuTopClose']).length === 0 ? showHint(parent, '#hhh_wordsHint', '关闭顶部弹幕') : showHint(parent, '#hhh_wordsHint', '打开顶部弹幕');
                        $(bb['danmukuTop']).click();
                    } else if(e.keyCode === 'B'.charCodeAt()) {  //开关底部弹幕
                        $(bb['danmukuBottomClose']).length === 0 ? showHint(parent, '#hhh_wordsHint', '关闭底部弹幕') : showHint(parent, '#hhh_wordsHint', '打开底部弹幕');
                        $(bb['danmukuBottom']).click();
                    } else if(e.keyCode === 'R'.charCodeAt()) {  //开关洗脑循环
                        $(`${bb['playSettingRepeat']}>${bb['switchInput']}`).click();
                    } else if(e.keyCode === 'Z'.charCodeAt()) {  //-弹幕透明度
                        window.setTimeout((function() {  //长按时保持DOM更新
                            opacity = adjust_progress(bb['settingOpacity'], -10);
                            if(opacity >= 0) showHint(parent, '#hhh_opacityHint', '透 '+opacity+'%');
                        }),0);
                    } else if(e.keyCode === 'C'.charCodeAt()) {  //+弹幕透明度
                        window.setTimeout((function() {
                            opacity = adjust_progress('div.bilibili-player-setting-opacity', 10);
                            if(opacity >= 0) showHint(parent, '#hhh_opacityHint', '透 '+opacity+'%');
                        }),0);
                    } else if(e.keyCode >= '1'.charCodeAt() && e.keyCode <= '5'.charCodeAt()) {  //弹幕显示区域
                        var s_type = {0:'1/4屏',25:'半屏',50:'3/4屏',75:'不重叠',100:'不限'};
                        var v = (e.keyCode - '1'.charCodeAt()) * 25;  //0-4*25
                        set_progress(bb['settingArea'], v);
                        showHint(parent, '#hhh_wordsHint', s_type[v]);
                    } else if(e.shiftKey === true && (e.keyCode === keycode['left'] || e.keyCode === keycode['right'])) {  //逐帧 shift+ left right
                        h5Player.pause();
                        h5Player.currentTime = e.keyCode === keycode['left']? h5Player.currentTime - 1/fps: h5Player.currentTime + 1/fps;
                    } else if(e.keyCode === 'X'.charCodeAt()) { //TEST
                        //$('.bilibili-player').attr('class', 'bilibili-player relative mode-webfullscreen bilibili-player-no-cursor');
                        //bilibili-player-area video-state-blackside progress-shadow-show
                    }else{
                        //console.dir(e);
                    }
//                 currentTime
//                 duration
//                 playbackRate
//                 volume
//                 paused
//                 pause()
//                 play()
//                 videoHeight
//                 videoWidth

                });

                //初始化关灯按钮
                lightoff_btn_css();

                //激活系统弹幕设置,以此使用网页全屏等
                $(bb['danmakuSetting']).mouseenter().mouseleave();

                //激活系统关灯设置,以此使用关灯等
                //去掉mouseout(),否则如果太快执行mouseout()无法激活关灯class,应该是mouseenter()未执行完就被mouseout打断了
                $(`${bb['playVideo']}${bb['playSetting']}`).mouseenter();

                //避免显示设置页面
                waitForNode(() => document.querySelector(bb['playSettingWrap']),
                            (node) => {
                    $(node).css({"visibility":"hidden"});  //visible
                })

                //解决因为激活关灯class,导致全屏时滚轮操作(系统自带)无法调节音量的问题
                waitForTrue(()=>$(bb['playSettingWrap']).css('display') === 'block',
                            () => {
                    $(bb['playSettingWrap']).css('display', 'none').css('visibility', 'visible');
                });

                //非全屏滚轮音量调节
                //两个参数指定屏幕范围(按百分比),第三个参数表示滚动一下增加的音量百分比,参数四表示暂停时是否调节
                if(config.getCheckboxSetting('volumeControlWhenNonFullScreen') === ON) wheel_volumeHint(0.30, 0.70, 3, config.getCheckboxSetting('volumeControlWhenPause'));

                //添加wordsHint opacityHint DOM
                $('#hhh_volumeHint').clone().appendTo(bb['videoWrap']).attr('id','hhh_wordsHint')
                                                                      .css({'opacity':0,'display':'none','width':'auto','margin-left':'0px','padding-left':'8px','padding-right':'15px','transform':'translate(-50%)'})
                                                                      .find('.bilibili-player-volumeHint-icon').remove().end()
                                                                      .find('.bilibili-player-volumeHint-text').css({'width': 'auto', 'padding-left': '10px'});
                $('#hhh_volumeHint').clone().appendTo(bb['videoWrap']).attr('id','hhh_opacityHint')
                                                                      .css({'opacity':0,'display':'none'})
                                                                      .find('.bilibili-player-volumeHint-icon').remove().end()
                                                                      .find('.bilibili-player-volumeHint-text').css({'padding-right': '6px'});

                //滚轮调节弹幕透明度(ctrl),参数表示滚动一下增加的透明度百分比,默认5
                if(config.getCheckboxSetting('danmuOpacityControl') === ON) wheel_opacity(5);

                //因为遮挡弹幕,去掉全屏时鼠标悬停时产生的顶端mask
                if(config.getCheckboxSetting('removeVideoTopMask') === ON) $(bb['videoTopMask']).removeClass();

                //添加自定义快捷键说明到右键菜单
                add_custom_hotkey_menu(config.hotKeyMenu);

                //播放关灯,暂停开灯
                player.addEventListener('video_media_playing', () => config.getCheckboxSetting('lightOffWhenPlaying') === ON && !is_lightoff() && lightoff_btn());
                player.addEventListener('video_media_pause', () => config.getCheckboxSetting('lightOnWhenPause') === ON && is_lightoff() && lightoff_btn());

                //自动运行
                if(config.getCheckboxSetting('autoPlay') === ON && $(`${bb['playSettingAutoplay']}>${bb['switchInput']}`)[0].checked === false)  //开启自动播放
                    $(`${bb['playSettingAutoplay']}>${bb['switchInput']}`).click();
                if(config.getCheckboxSetting('repeat') === ON) $(`${bb['playSettingRepeat']}>${bb['switchInput']}`).click();  //开启洗脑循环
                if(config.getCheckboxSetting('lightOff') === ON) lightoff_btn();  //自动关灯

            }, 10000);
        }
        //初始化
        function init() {
            //内部加载视频窗口
            waitForNode(() => document.querySelector('video'),
                        (node) => {
                var oV = document.getElementsByTagName("video")[0];
                oV.addEventListener('DOMNodeInserted', () => {
                    run();
                });
            });

            run();
        }

        init();
    }
}

hhh_lightoff_main.init();