bilibili关灯

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

目前為 2021-06-29 提交的版本,檢視 最新版本

// ==UserScript==
// @name         bilibili关灯
// @namespace    hhh2000
// @version      0.7.4
// @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-start
// @grant        none
// ==/UserScript==

'use strict';
hhh_lightoff_main = {
    init() {
        var //config
            ON = true,
            OFF = false,
            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: OFF, tips: '' },
                        lightOff: { text: '自动关灯', status: ON, tips: '' },
                        volumeControlWhenNonFullScreen: { text: '开启非全屏音量调节', status: ON, tips: '' },
                        danmuOpacityControl: { text: '开启弹幕透明度控制', status: ON, tips: '' },  //ctrl+滚轮
                        removeVideoTopMask: { text: '去掉顶部mask', status: ON, tips: '' }
                    },
                    btn: '设置'
                }
            };

        function abc(e) {console.log(e)}
        function waitForNode(nodeSelector, callback) {
            var node = nodeSelector();
            if (node) {
                callback(node);
            } else {
                setTimeout(function() { waitForNode(nodeSelector, callback); }, 100);
            }
        }
        function waitForTrue(ifTrue, callback) {
            if (ifTrue()) {
                callback();
            } else {
                setTimeout(function() { waitForTrue(ifTrue, callback); }, 100);
            }
        }
        function is_lightoff() { return !player.getPlayerState().lightOn; }
        function lightoff() { $('.bilibili-player-video-btn-setting-right-others-content-lightoff input').click(); }
        //关灯按钮样式
        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>.bui-switch-input')[0].checked === false) {  //关灯
                $('#hhh_lightoff .bui-switch-body:first').css('background-color', dark_rgb);
                $('#hhh_lightoff .bui-switch-body:first>.bui-switch-dot').css('color', dark_rgb);
            }
            else {
                $('#hhh_lightoff .bui-switch-body:first').css('background-color', body_brgb);
                $('#hhh_lightoff .bui-switch-body:first>.bui-switch-dot').css({'color': dot_crgb, 'background-color': dot_brgb});
            }
        }
        //关灯按钮
        function lightoff_btn() {
            lightoff();
            if(is_lightoff() === $('#hhh_lightoff>.bui-switch-input')[0].checked) {  //checked==true开灯 false关灯
                $('#hhh_lightoff>.bui-switch-input')[0].checked = !$('#hhh_lightoff>.bui-switch-input')[0].checked;
            }
            lightoff_btn_css();
        }
        //显示提示
        function showHint(parent, selector_str, text){
            $(".bilibili-player-volumeHint").css('display', 'none');  //隐藏所有提示,避免重叠
            $(selector_str+'>.bilibili-player-volumeHint-text').text(text);  //百分比显示
            //$(selector_str+'>.bilibili-player-volumeHint-text').css({'position': 'relative', 'left': '-10px'});
            //$(selector_str).width(100);
            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
        function wheel_volumeHint(screenLeft, screenRight){
            //div(抄bilibili^^)
            var volumeHint = '<div id=hhh_volumeHint class="bilibili-player-volumeHint" style="opacity: 0; display: none;">\n'+
                '   <span class="bilibili-player-volumeHint-icon video-state-volume-max">\n'+
                '       <i class="bilibili-player-iconfont bilibili-player-iconfont-volume icon-24soundsmall"></i>\n'+
                '       <i class="bilibili-player-iconfont bilibili-player-iconfont-volume-max icon-24soundlarge"></i>\n'+
                '       <i class="bilibili-player-iconfont bilibili-player-iconfont-volume-min icon-24soundoff"></i>\n'+
                '   </span>\n'+
                '   <span class="bilibili-player-volumeHint-text">57%</span>\n'+
                '</div>';
            if($('#hhh_volumeHint').length === 0) $('.bilibili-player-video-wrap').append(volumeHint);

            //add wheelevent
            $('.bilibili-player-video-wrap').off('mousewheel.hhh_volumeHint');
            $('.bilibili-player-video-wrap').on('mousewheel.hhh_volumeHint', function(e){
                if (player.isFullScreen() === true) {  //全屏退出
                    $(".bilibili-player-volumeHint").css('display', 'none');  //隐藏所有提示,避免重叠
                    return;
                }
                if(e.ctrlKey || e.altKey || e.shiftKey) return;
                //屏幕百分比参数
                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 }
                //非暂停 && 鼠标在屏幕指定位置时处理
                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.getState() !== 'PAUSED' && inLimit) {
                    e.preventDefault();  //阻止页面滚动
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var volume = player.volume();
                    if(wheelDelta >= 120) {  //向上滚动,减少音量
                        player.volume(volume+0.03);
                    } else if(wheelDelta <= -120) {  //向下滚动,增大音量
                        player.volume(volume-0.03);
                    }
                    showHint(this, '#hhh_volumeHint', Math.round(player.volume()*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 danmaku_setting_wrap = '.bilibili-player-video-danmaku-setting-wrap';
            var tip_selector = document.querySelector(selector_str+' .bui-thumb-tooltip');

            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;  //进度条对应百分比的系统算法
            }

            $(danmaku_setting_wrap).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);

            $(danmaku_setting_wrap).css({"display":"none"});

            $('.bilibili-player-video-danmaku-setting').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');
            var danmaku_setting_wrap = '.bilibili-player-video-danmaku-setting-wrap';

            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;  //进度条对应百分比的系统算法
            }

            $(danmaku_setting_wrap).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);

            $(danmaku_setting_wrap).css({"display":"none"});

            $('.bilibili-player-video-danmaku-setting').mouseleave();  //激活设置,记忆进度条位置
        }
        //滚轮调节弹幕透明度(ctrl)
        function wheel_opacity(){
            //add wheelevent
            $('.bilibili-player-video-wrap').off('mousewheel.hhh_opacity');
            $('.bilibili-player-video-wrap').on('mousewheel.hhh_opacity', function(e){
                if(e.ctrlKey === true) {
                    e.preventDefault();  //阻止页面滚动
                    e.stopPropagation();  //阻止冒泡
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var opacity = -1;
                    if(wheelDelta >= 120) {  //向上滚动,增大透明度
                        opacity = adjust_progress('div.bilibili-player-setting-opacity', 5);
                    } else if(wheelDelta <= -120) {  //向下滚动,减少透明度
                        opacity = adjust_progress('div.bilibili-player-setting-opacity', -5);
                    }
                    if(opacity >= 0) showHint(document, '#hhh_opacityHint', '透 '+opacity+'%');
                }
            });
        }
        //主程序
        function run(){
            waitForNode(() => document.querySelector('.bilibili-player-video-danmaku-switch .bui-switch-dot'),
                        (node) => {

                //保存设置信息
                config.saveCheckboxSetting();

                //防止重复加载,不精确,可能跟其他插件冲突
                if ($('.bilibili-player-video-danmaku-switch .bui-switch-dot').length !== 1) return;

                //插入关灯按钮
                $("div.bilibili-player-video-danmaku-switch:first").clone().prependTo("div.bilibili-player-video-danmaku-root:first");
                $("div.bilibili-player-video-danmaku-switch:first")[0].id = 'hhh_lightoff';
                $('#hhh_lightoff .bui-switch-dot>span').remove();
                $('#hhh_lightoff .bui-switch-dot')[0].innerHTML = '灯';

                //点击关灯
                $('#hhh_lightoff>.bui-switch-input:first').click(function(){ lightoff_btn() });

                //键盘关灯等
                var opacity;
                var parent = document;
                $(document).off('keydown.hhh_lightoff');
                $(document).on('keydown.hhh_lightoff',function(e){
                    if(e.keyCode === 'A'.charCodeAt()){  //开关灯
                        is_lightoff() ? showHint(parent, '#hhh_wordsHint', '开灯') : showHint(parent, '#hhh_wordsHint', '关灯');
                        lightoff_btn();
                    } else if(e.keyCode === 'W'.charCodeAt()) {  //网页全屏
                        $('.bilibili-player-video-web-fullscreen').click();
                    } else if(e.keyCode === 'Q'.charCodeAt()) {  //宽屏模式
                        player.isFullScreen() ? $('.bilibili-player-video-web-fullscreen').click() : $('.bilibili-player-video-btn-widescreen').click();
                    } else if(e.keyCode === 'D'.charCodeAt()) {  //开关弹幕
                        $('.bilibili-player-video-danmaku-switch>.bui-switch-input:last').click();
                        player.getPlayerState().danmaku.show === true ? showHint(parent, '#hhh_wordsHint', '开弹幕') : showHint(parent, '#hhh_wordsHint', '关弹幕');
                    } else if(e.keyCode === 'T'.charCodeAt()) {  //开关顶部弹幕
                        $('.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_top_close]').length === 0 ? showHint(parent, '#hhh_wordsHint', '关闭顶部弹幕') : showHint(parent, '#hhh_wordsHint', '打开顶部弹幕');
                        $('.bilibili-player-block-filter-type[ftype=top]').click();
                    } else if(e.keyCode === 'B'.charCodeAt()) {  //开关底部弹幕
                        $('.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_bottom_close]').length === 0 ? showHint(parent, '#hhh_wordsHint', '关闭底部弹幕') : showHint(parent, '#hhh_wordsHint', '打开底部弹幕');
                        $('.bilibili-player-block-filter-type[ftype=bottom]').click();
                    } else if(e.keyCode === 'R'.charCodeAt()) {  //开关洗脑循环
                        $(".bilibili-player-video-btn-setting-left-repeat>.bui-switch-input").click();
                    } else if(e.keyCode === 'Z'.charCodeAt()) {  //-弹幕透明度
                        window.setTimeout((function() {  //长按时保持DOM更新
                            opacity = adjust_progress('div.bilibili-player-setting-opacity', -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()) {  //1/4屏
                        set_progress('.bilibili-player-setting-area', 0);
                        showHint(parent, '#hhh_wordsHint', '1/4屏');
                    } else if(e.keyCode === '2'.charCodeAt()) {  //半屏
                        set_progress('.bilibili-player-setting-area', 25);
                        showHint(parent, '#hhh_wordsHint', '半屏');
                    } else if(e.keyCode === '3'.charCodeAt()) {  //3/4屏
                        opacity = set_progress('.bilibili-player-setting-area', 50);
                        showHint(parent, '#hhh_wordsHint', '3/4屏');
                    } else if(e.keyCode === '4'.charCodeAt()) {  //不重叠
                        opacity = set_progress('.bilibili-player-setting-area', 75);
                        showHint(parent, '#hhh_wordsHint', '不重叠');
                    } else if(e.keyCode === '5'.charCodeAt()) {  //不限
                        opacity = set_progress('.bilibili-player-setting-area', 100);
                        showHint(parent, '#hhh_wordsHint', '不限');
                    } else if(e.keyCode === 38 || e.keyCode === 40) {  //up+down arrow 系统音量提示显示时隐藏自定义音量提示
                        $(".bilibili-player-volumeHint").css('display', 'none');
                    }
                });

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

                //一些CLASS命名
                var danmaku_setting    = '.bilibili-player-video-danmaku-setting';
                var video_setting      = '.bilibili-player-video-btn.bilibili-player-video-btn-setting';
                var video_setting_wrap = '.bilibili-player-video-btn-setting-wrap';

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

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

                //避免显示激活页面
                waitForNode(() => document.querySelector(video_setting_wrap),
                            (node) => {
                    $(node).css({"visibility":"hidden"});  //visible
                })

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

                //非全屏滚轮音量调节
                //两个参数指定屏幕范围(按百分比)
                if(config.getCheckboxSetting('volumeControlWhenNonFullScreen') === ON) wheel_volumeHint(0.30, 0.70);

                //添加wordsHint opacityHint DOM(抄bilibili^^)
                var div_wordsHint = '<div id=hhh_wordsHint class="bilibili-player-volumeHint" style="opacity: 0; display: none; width: auto; margin-left: 0px; padding-left:15px; padding-right:15px; transform: translate(-50%);">\n'+
                    '   <span class="bilibili-player-volumeHint-text" style="width: auto; padding-left: c10px;">57%</span>\n'+
                    '</div>';
                if($('#hhh_wordsHint').length === 0) $('.bilibili-player-video-wrap').append(div_wordsHint);
                var div_opacityHint = '<div id=hhh_opacityHint class="bilibili-player-volumeHint" style="opacity: 0; display: none;">\n'+
                    '   <span class="bilibili-player-volumeHint-text" style="padding-right: 6px">57%</span>\n'+
                    '</div>';
                if($('#hhh_opacityHint').length === 0) $('.bilibili-player-video-wrap').append(div_opacityHint);

                //滚轮调节弹幕透明度(ctrl)
                if(config.getCheckboxSetting('danmuOpacityControl') === ON) wheel_opacity();

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

                //addEventListener
                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 && $('.bilibili-player-video-btn-setting-left-autoplay>.bui-switch-input')[0].checked === false)  //开启自动播放
                    $(".bilibili-player-video-btn-setting-left-autoplay>.bui-switch-input").click();
                if(config.getCheckboxSetting('repeat') === ON) $(".bilibili-player-video-btn-setting-left-repeat>.bui-switch-input").click();  //开启洗脑循环
                if(config.getCheckboxSetting('lightOff') === ON) lightoff_btn();  //自动关灯

                //解决自动播放时,自动关灯不响应的问题**
                //config.getCheckboxSetting('lightOffWhenPlaying') && $('.bilibili-player-video-btn-setting-left-autoplay>.bui-switch-input')[0].checked && !is_lightoff() && lightoff_btn();

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

            run();
        }
        init();
    }
}

window.onload = hhh_lightoff_main.init();