bilibili关灯

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

目前为 2021-07-11 提交的版本。查看 最新版本

// ==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();

QingJ © 2025

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