bilibili关灯及快捷操作

bilibili关灯及快捷操作(把被新版B站藏起来的关灯按钮揪出来,在关闭弹幕按钮左边,还可以用快捷键,默认'A')、非全屏滚轮音量控制、弹幕控制快捷操作等

目前為 2022-04-23 提交的版本,檢視 最新版本

// ==UserScript==
// @name         bilibili关灯及快捷操作
// @namespace    hhh2000
// @version      0.9.6.4
// @description  bilibili关灯及快捷操作(把被新版B站藏起来的关灯按钮揪出来,在关闭弹幕按钮左边,还可以用快捷键,默认'A')、非全屏滚轮音量控制、弹幕控制快捷操作等
// @author       hhh2000
// @include      http*://www.bilibili.com/*
// @include      http*://www.bilibili.com/video/av*
// @include      http*://www.bilibili.com/video/BV*
// @include      http*://www.bilibili.com/watchlater/*
// @include      http*://www.bilibili.com/medialist/play/*
// @include      http*://www.bilibili.com/bangumi/play/ep*
// @include      http*://www.bilibili.com/bangumi/play/ss*
// @include      http*://bangumi.bilibili.com/anime/*/play*
// @include      http*://bangumi.bilibili.com/movie/*
// @include      http*://www.bilibili.com/blackboard/*
// @include      http*://t.bilibili.com/*
// @include      http*://space.bilibili.com/*
// @include      http*://www.bilibili.com/video/online.html*
// @include      http*://www.bilibili.com/account/history
// @include      http*://api.bilibili.com/*
// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
/* globals jQuery, $, waitForkeyElements */
/* eslint-disable no-multi-spaces, dot-notation */
// @run-at       document-end
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @grant        none
// ==/UserScript==

'use strict';
var hhh_lightoff_main = {
    init() {
        var //
            ver,
            fps,
            h5Player,
            curr_focus,
            is_in_biliplayer,
            is_show_hint,
            $tip,
            move_frames;
        //const [BILI_2_X_V2, BILI_3_X, ALL] = ['bili_2.x', 'bili_3.x', 'all'];
        const [BILI_2_X_V2, BILI_2_X_V3, BILI_2_X, BILI_3_X, ALL] = ['bili_2.x.v2', 'bili_2.x.v3', 'bili_2.x', 'bili_3.x', 'all'];
        var //切换番剧和一般视频class
            bb = {},
            bb_type = '',
            bb_config = {
                bb_class_data: {  //其实这样不方便调试
                    //'player':{BILI_2_X_V2:'.player', [BILI_3_X]:'.bpx-player'}, //main

                    //$('meta[property="og:image"]').attr('content')
                    'coverImg':{[ALL]:'meta[property="og:image"]'}, //封面

                    'playTipWrap':{[BILI_2_X]  :'.bilibili-player-dm-tip-wrap', [BILI_3_X]:'.bpx-player-video-perch'}, //paly/pause
                    'fullScreen':{[BILI_2_X]   :'.bilibili-player-video-btn-fullscreen', [BILI_3_X]:'.squirtle-video-fullscreen.squirtle-video-item'}, //全屏
                    'webFullScreen':{[BILI_2_X]:'.bilibili-player-video-web-fullscreen', [BILI_3_X]:'.squirtle-video-pagefullscreen.squirtle-video-item'}, //网页全屏
                    'wideScreen':{[BILI_2_X]   :'.bilibili-player-video-btn-widescreen', [BILI_3_X]:'.squirtle-video-widescreen.squirtle-video-item'}, //宽屏

                    //一健三联
                    'like'   :{[BILI_2_X_V2]:'.ops .like'   , [BILI_2_X_V3]:'.toolbar-left .like'   , [BILI_3_X]:'.like-info'}, //点赞
                    'likeon' :{[BILI_2_X_V2]:'.ops .like.on', [BILI_2_X_V3]:'.toolbar-left .like.on', [BILI_3_X]:'.like-info.active'}, //已点赞
                    'coin'   :{[BILI_2_X_V2]:'.ops .coin'   , [BILI_2_X_V3]:'.toolbar-left .coin'   , [BILI_3_X]:'.coin-info'}, //硬币
                    'collect':{[BILI_2_X_V2]:'.ops .collect', [BILI_2_X_V3]:'.toolbar-left .collect', [BILI_3_X]:''}, //收藏

                    //弹幕
                    'danmukuTopClose':{[BILI_2_X]:'.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_top_close]', [BILI_3_X]:'.bpx-player-block-filter-type.bpx-player-block-typeTop.bpx-player-active'}, //顶部弹幕
                    'danmukuTop'     :{[BILI_2_X]:'.bilibili-player-block-filter-type[ftype=top]', [BILI_3_X]:'.bpx-player-block-filter-type.bpx-player-block-typeTop'}, //顶部弹幕
                    'danmukuBottomClose':{[BILI_2_X]:'.bilibili-player-block-filter-type[data-name=ctlbar_danmuku_bottom_close]', [BILI_3_X]:'.bpx-player-block-filter-type.bpx-player-block-typeBottom.bpx-player-active'}, //底部弹幕
                    'danmukuBottom'     :{[BILI_2_X]:'.bilibili-player-block-filter-type[ftype=bottom]', [BILI_3_X]:'.bpx-player-block-filter-type.bpx-player-block-typeBottom'}, //底部弹幕
                    'progressVal'   :{[ALL]:'.bui-progress-val'}, //弹幕透明度读数
                    'progressWrap'  :{[ALL]:'.bui-progress-wrap'}, //弹幕透明度进度条
                    'settingOpacity':{[BILI_2_X]:'.bilibili-player-setting-opacity', [BILI_3_X]:'.bpx-player-dm-setting-ui-opacity'}, //弹幕透明度
                    'settingFontsize':{[BILI_2_X]:'.bilibili-player-setting-fontsize', [BILI_3_X]:'.bpx-player-dm-setting-ui-fontsize'}, //弹幕字号
                    'settingArea'   :{[BILI_2_X]:'.bilibili-player-setting-area', [BILI_3_X]:'.bpx-player-dm-setting-ui-area'}, //显示区域
                    'settingFs'     :{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-fs input', [BILI_3_X]:'.bpx-player-dm-setting-left-fs input'}, //弹幕随屏幕缩放

                    //音量
                    'volumeHint'    :{[BILI_2_X]:'.bilibili-player-volumeHint', [BILI_3_X]:'.bpx-player-volume-hint'}, //音量显示
                    'volumeHintText':{[BILI_2_X]:'.bilibili-player-volumeHint-text', [BILI_3_X]:'.bpx-player-volume-hint-text'}, //音量显示百分比读数
                    'volumeHintIcon':{[BILI_2_X]:'.bilibili-player-volumeHint-icon', [BILI_3_X]:'.bpx-player-volume-hint-icon'}, //音量显示图标
                    'volumebarWrp'  :{[BILI_2_X]:'.bilibili-player-video-volumebar-wrp', [BILI_3_X]:'.squirtle-volume-bar-wrap'}, //音量条
                    'volumeNum'     :{[BILI_2_X]:'.bilibili-player-video-volume-num', [BILI_3_X]:'.squirtle-volume-num'}, //音量读数

                    //视频速度
                    'videoSpeedActive':{[BILI_2_X]:'.bilibili-player-video-btn-speed-menu-list.bilibili-player-active', [BILI_3_X]:'.squirtle-speed-select-list .squirtle-select-item.active'}, //视频速度
                    'videoSpeed':{[BILI_2_X]:'.bilibili-player-video-btn-speed-menu-list', [BILI_3_X]:'.squirtle-speed-select-list .squirtle-select-item'}, //视频速度
                    'videoSpeedName':{[BILI_2_X]:'.bilibili-player-video-btn-speed-name', [BILI_3_X]:'.squirtle-select-result.squirtle-speed-select-result'}, //视频速度

                    //弹幕设置等
                    'switchBody':{[ALL]:'.bui-switch-body'}, //系统关灯css设置
                    'switchDot':{[ALL]:'.bui-switch-dot'}, //系统弹幕设置按钮wrap进度条拖动点

                    'switchInput':{[BILI_2_X_V3]:'.bui-danmaku-switch-input', [ALL]:'.bui-switch-input'}, //弹幕设置switch按钮
                    'switchLabel':{[BILI_2_X_V3]:'.bui-danmaku-switch-label', [ALL]:'.bui-switch-label'}, //弹幕设置switchLabel

                    'danmaku':{[BILI_2_X]:'.bilibili-player-video-danmaku', [BILI_3_X]:'.bpx-player-row-dm-wrap'}, //弹幕
                    'danmakuRoot':{[BILI_2_X]:'.bilibili-player-video-danmaku-root', [BILI_3_X]:'.bpx-player-dm-root'}, //系统弹幕设置条
                    'danmakuSwitch':{[BILI_2_X]:'.bilibili-player-video-danmaku-switch', [BILI_3_X]:'.bpx-player-dm-switch'}, //关闭弹幕按钮

                    'dm':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting', [BILI_3_X]:'.bpx-player-dm-setting'}, //系统弹幕设置按钮
                    'dmWrap':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-wrap', [BILI_3_X]:'.bpx-player-dm-setting-wrap'}, //系统弹幕设置wrap
                    'dmBox':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-box', [BILI_3_X]:'.bpx-player-dm-setting-box'}, //系统弹幕设置box
                    'dmLeft':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left', [BILI_3_X]:'.bpx-player-dm-setting-left'},
                    'dmLeftMore':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-more', [BILI_3_X]:'.bpx-player-dm-setting-left-more'},
                    'dmLeftMoreText':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-more-text', [BILI_3_X]:'.bpx-player-dm-setting-left-more-text'},
                    'dmLeftBlock':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-block', [BILI_3_X]:'.bpx-player-dm-setting-left-block'},
                    'dmLeftBlockTitle':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-block-title', [BILI_3_X]:'.bpx-player-dm-setting-left-block-title'},
                    'dmLeftFlagTitle':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-left-flag-title', [BILI_3_X]:'.bpx-player-dm-setting-left-flag-title'},
                    'dmRightMore':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-right-more', [BILI_3_X]:'.bpx-player-dm-setting-right-more'},
                    'dmRightMoreText':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-right-more-text', [BILI_3_X]:'.bpx-player-dm-setting-right-more-text'},
                    'dmRightSeparator':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-right-separator', [BILI_3_X]:'.bpx-player-dm-setting-right-separator'},
                    'dmRightReset':{[BILI_2_X]:'.bilibili-player-video-danmaku-setting-right-reset', [BILI_3_X]:'.bpx-player-dm-setting-right-reset'},

                    'videoWrap':{[BILI_2_X]:'.bilibili-player-video-wrap', [BILI_3_X]:'.bpx-player-video-area'}, //播放wrap
                    'videoContextMenu':{[BILI_2_X]:'.bilibili-player-video-wrap', [BILI_3_X]:'.bpx-player-video-perch'}, //播放contextmenu
                    'video':{[BILI_2_X]:'.bilibili-player-video', [BILI_3_X]:'.bpx-player-video-wrap'}, //播放
                    'videoTopMask':{[BILI_2_X]:'.bilibili-player-video-top-mask', [BILI_3_X]:'.bpx-player-top-mask'}, //全屏时鼠标悬停时产生的顶端mask

                    //系统设置等
                    'playArea':{[ALL]:'.bilibili-player-area'}, //哔哩哔哩播放器
                    'playVideo':{[BILI_2_X]:'.bilibili-player-video-btn'}, //系统设置
                    'playVideoControlWrap':{[BILI_2_X]:'.bilibili-player-video-control-wrap', [BILI_3_X]:'.bpx-player-control-wrap'}, //系统控制面板
                    'playSetting':{[BILI_2_X]:'.bilibili-player-video-btn-setting'}, //系统播放设置
                    'playSettingWrap':{[BILI_2_X]:'.bilibili-player-video-btn-setting-wrap'}, //系统播放设置wrap
                    'playSettingAutoplay':{[BILI_2_X]:'.bilibili-player-video-btn-setting-left-autoplay input', [BILI_3_X]: '.squirtle-setting-autoplay'}, //自动播放
                    'playSettingRepeatInput':{[BILI_2_X]:'.bilibili-player-video-btn-setting-left-repeat input', [BILI_3_X]:'.squirtle-setting-loop'}, //洗脑循环按钮
                    'playSettingLightoff':{[BILI_2_X]:'.bilibili-player-video-btn-setting-right-others-content-lightoff input', [BILI_3_X]:'.squirtle-single-setting-other-choice.squirtle-lightoff'}, //关灯按钮
                    'bpxStateLightOff':{[BILI_3_X]:'.bpx-state-light-off'}, //关灯bpx
                    'playJumpElectric':{[BILI_2_X]:'.bilibili-player-electric-panel-jump'}, //2.69.4版本B站取消充电鸣谢,2.72又加回来了

                    //右键菜单
                    'playerContextMenu':{[BILI_2_X]:'.bilibili-player-context-menu-container.black.bilibili-player-context-menu-origin', [BILI_3_X]:'.bpx-player-contextmenu.bpx-player-black'}, //右键菜单
                    'hotkeyPanel':{[BILI_2_X]:'.bilibili-player-hotkey-panel-container', [BILI_3_X]:'.bpx-player-hotkey-panel'}, //快捷键说明面板
                    'hotkeyPanelClose':{[BILI_2_X]:'.bilibili-player-hotkey-panel-close', [BILI_3_X]:'.bpx-player-hotkey-panel-close'}, //快捷键说明面板关闭按钮
                    'videoInfo':{[BILI_2_X]:'.bilibili-player-video-info', [BILI_3_X]:'.bpx-player-info'}, //视频统计信息
                    'videoInfoClose':{[BILI_2_X]:'.bilibili-player-video-info-close', [BILI_3_X]:'.bpx-player-info-close'}, //视频统计信息关闭按钮
                    'videoInfoContainer':{[BILI_2_X]:'.bilibili-player-video-info-container', [BILI_3_X]:'.bpx-player-info-container'}, //视频统计信息
                    'videoInfoShow':{[BILI_2_X]:'.bilibili-player-video-info-container active', [BILI_3_X]:'.bpx-player-info-container'}, //视频统计信息面板显示
                    'DOMNodeInsertedVideoInfoShow':{[BILI_2_X]:'.bilibili-player-video-info-container active', [BILI_3_X]:'.info-line'}, //
                },
                set_bb(_bb_type) {
                    bb_type = _bb_type;
                    for(var k in this.bb_class_data){
                        var class_str = this.bb_class_data[k][bb_type] || this.bb_class_data[k][[BILI_2_X]] || this.bb_class_data[k][[ALL]];
                        bb[k] = class_str;
                    }
                }
           };

        const [ON, OFF] = [true, false];
        var //config
            keycode = {
                'Enter': 13,
                'Ctrl': 17,
                'Esc': 27,
                'left': 37,
                'right': 39,
                'up': 38,
                'down': 40,
                'space': 32,
                '/': 191,
            },
            config = {
                //一些主要开关设置
                sets: {},
                getCheckboxSettingStatus(key) {
                    return this.sets[key]['status'];
                },
                getCheckboxSettingFn(key) {
                    return this.sets[key]['fn'];
                },
                getCheckboxSettingArgs(key) {
                    return this.sets[key]['args'];
                },
                setCheckboxSettingStatus(key, status) {
                    this.sets[key]['status'] = status;
                },
                setCheckboxSettingTips(key, tips) {
                    this.sets[key]['tips'] = tips;
                },
                saveCheckboxSetting() {
                    for(var o in this){
                        if(o.indexOf('b_') === 0){
                            this.sets = JSON.parse(JSON.stringify(this[o]['options']));
                        }
                    }
                },
                b_playerCheckbox: {
                    options: {
                        autoPlay: { text: '自动播放', status: OFF, tips: '' },
                        lightOff: { text: '自动关灯', status: OFF, tips: '' },
                        autoFullScreen: { text: '自动全屏', status: OFF, tips: '' },
                        autoWebFullScreen: { text: '自动网页全屏', status: OFF, tips: '' },
                        videoRepeat: { text: '自动洗脑循环', status: OFF, tips: '' },
                        lightOffWhenPlaying: { text: '播放时自动关灯', status: OFF, fn: 'lightOffWhenPlaying' },
                        lightOnWhenPause: { text: '暂停时自动开灯', status: OFF, fn: 'lightOnWhenPause' },
                        rememberVideoRepeat: { text: '记忆洗脑循环', status: ON, tips: '优先级低于【自动洗脑循环】', show: OFF }, //优先级低于videoRepeat
                        dblclickFullScreen: { text: '双击或中键全屏', status: ON, tips: '', fn: 'dblclickFullScreen' },
                        volumeControlWhenNonFullScreen: { text: '非全屏滚轮音量调节', status: ON, tips: '', fn: 'wheel_volumeHint', args:{screenLeft: 0.3, screenRight: 0.7, delta: 1} },
                        volumeControlWhenPause: { text: '非全屏暂停时滚轮音量调节', status: ON, tips: '' },
                        danmuOpacityControl: { text: '滚轮弹幕透明度控制', status: ON, tips: 'Ctrl + 滚轮', fn: 'wheel_opacity', args:{delta: 5} }, //ctrl+滚轮
                        keyVideoSpeed: { text: '键盘调节视频速度', status: ON, tips: 'Ctrl + ↑↓' },
                        removeVideoTopMask: { text: '去掉顶部mask', status: ON, tips: '', fn: 'removeVideoTopMask' },
                        jumpElectric: { text: '跳过充电鸣谢', status: ON, fn: 'jumpElectric' }, //2.69.4版本B站取消充电鸣谢,2.72又加回来了
                        reloadDanmuku: { text: '快进快退恢复重载弹幕效果', status: OFF }, //快进快退恢复重载弹幕效果
                        //removeMostViewedListener: { text: '删除动态首页UP主动态提示', status: ON },
                        //不显示有明显变化的提示,关灯、关弹幕等,因为对有些人来说这些操作变化明显可见,提示反而多余且遮挡屏幕
                        hotKeyHint: { text: '快捷键屏幕提示', status: OFF, tips: '不显示有明显变化的提示,关灯、关弹幕等' },
                        openHotKey: { text: '开启自定义快捷键', status: ON, tips: '', 'fn': 'set_hotkey' },
                    },
                    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函数
                    'volumeControl': { value: '滚轮', text: '音量调节', },
                    'lightOff': { value: 'A', text: '关灯/开灯', },
                    'webFullscreen': { value: 'W', text: '网页全屏', },
                    'widescreen': { value: 'Q', text: '宽屏模式', },
                    'danmu': { value: 'D', text: '弹幕/关闭弹幕', },
                    'danmuTopBottom': { value: 'T/B', text: '顶部/底部弹幕', },
                    'videoRepeat': { value: 'R', text: '洗脑循环', },
                    'addsubDanmuOpacity': { value: 'Z/C', text: '减增弹幕透明度10%', },
                    'addsubDanmuFontsize': { value: 'V/N', text: '减增弹幕字号10%', },
                    'danmuArea': { value: '1、2、3、4、5', text: '弹幕显示区域 1/4屏~不限', },
                    // '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: '增减弹幕透明度5%', },
                    'fastForwardBackward30s': { value: 'Ctrl + ←/→', text: '快进/快退30s', },
                    '1/FPS': { value: 'Shift + ←/→', text: '逐帧操作', },
                    'keyVideoSpeed': { value: 'Ctrl + ↑/↓', text: '调节视频播放速度', },
                    'dblclickFullScreen': { value: '双击/中键/功能键', text: '全屏', },
                    'ctrl_enterFullScreen': { value: 'Ctrl+Enter', text: '全屏', },
                    'danmuZoomWithScreen': { value: 'S', text: '弹幕是否随屏幕缩放', },
                    'like': { value: 'Y、U、I、O', text: '点赞、投币、收藏、长按一键三连', },
                    'loop': { value: 'Ctrl + 左键 / L', text: '设定段落循环 / 设定后切换', },
                },
            };
        const assert = function(condition, message) {
            if (!condition)
                throw Error('Assert failed: ' + (message || 'Assertion failed'));
        }
        function log(e) {console.log(e)}
        function dir(e) {console.dir(e)}
        function set_value(key, value){ localStorage.setItem(key, value) }
        function get_value(key, default_value){ return localStorage.getItem(key) || default_value }

        function waitForNode(nodeSelector, callback, times) {
            //log('----n---');
            if(times < 0) return;
            var node = nodeSelector();
            if (node) {
                callback(node);
            } else {
                times-=1;
                setTimeout(function() { waitForNode(nodeSelector, callback, times); }, 50);
            }
        }
        function waitForTrue(ifTrue, callback) {
            //log('----t---');
            if (ifTrue()) {
                callback();
            } else {
                setTimeout(function() { waitForTrue(ifTrue, callback); }, 50);
            }
        }
        function is_fullscreen() {
            //if(bb_type.indexOf(BILI_2_X) !== -1){ return bili_player.isFullScreen() }
            if(bb_type.indexOf(BILI_2_X) !== -1){ return $('#bilibiliPlayer').hasClass('mode-webfullscreen') || $('#bilibiliPlayer').hasClass('mode-fullscreen')  }
            else if(bb_type === BILI_3_X){ return $('.bpx-player-container').attr('data-screen') === 'web' || $('.bpx-player-container').attr('data-screen') === 'full' }  //normal wide web full
        }
        function fullscreen() { $(bb['fullScreen']).click() }
        function web_fullscreen() { $(bb['webFullScreen']).click() }
        function wide_screen() { $(bb['wideScreen']).click() }
        function is_lightoff() {
            //if (bb_type.indexOf(BILI_2_X) !== -1) { return !bili_player.getPlayerState().lightOn }
            if (bb_type.indexOf(BILI_2_X) !== -1) { return $('#bilibiliPlayer').hasClass('mode-light-off') }
            else if(bb_type === BILI_3_X) { return $(bb['playSettingLightoff']).hasClass('active') }
        }
        function is_danmaku_show(){
            return $(bb['danmakuSwitch']+' '+bb['switchInput']+':last')[0].checked;
        }
        function lightoff() {
            $(bb['playSettingLightoff']).click()
        }
        function add_tip($tip, $node, args){
            $node.mouseover(function(){
                var e = this;
                var op = {};
                let t = setTimeout(function() {
                    $tip.appendTo(e);
                    let $this = $(e);
                    let $new_tip = $('.player-tooltips.tip.top-center.animation').css({top:0,left:0});

                    true === !!$this.data('tip') ? $.extend(true, op, $this.data('tip')) : $.extend(true, op, args);
                    $new_tip.find('.tooltip').text(op['text']);

                    let tip_new_top = $this.offset().top - $new_tip.offset().top - $new_tip.height();
                    //console.log('top:'+$this.offset().top+' tiptop: '+$new_tip.offset().top +' height: '+ $new_tip.height());
                    //console.log('left:'+$this.offset().left+' tipleft: '+$new_tip.offset().left +' width: '+ $this.width()+' tipwidth: '+ $new_tip.width());
                    //console.log('top:'+$this.css('top')+'left:'+$this.css('left'))
                    let tip_new_left = $this.offset().left - $new_tip.offset().left + ($this.width() - $new_tip.width())/2;
                    //console.log(tip_new_top+'  '+tip_new_left);
                    tip_new_left = tip_new_left <= 0 ? 0 : tip_new_left;
                    let diff_full_top = is_fullscreen() ? (op['diff_full_top'] || 0) : 0; //全屏时位置不同
                    $new_tip.css({'top':tip_new_top + op['top'] + diff_full_top, 'left':tip_new_left + op['left']}).addClass('active');
                }, op['millisec']);
                $(this).data('timeout', t);
            }).
            mouseout(function(e){
                clearTimeout($(this).data('timeout'));
                $('.player-tooltips.tip.top-center.animation').removeClass('active');
                $('.player-tooltips.tip.top-center.animation').remove();
            })
        }
        //关灯按钮样式
        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);
                $(`#hhh_lightoff ${bb['switchLabel']}`).removeClass('checked');
            }
            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});
                $(`#hhh_lightoff ${bb['switchLabel']}`).addClass('checked');
            }
        }
        //关灯按钮
        function lightoff_btn() {
            lightoff();
            let $light_input = $('#hhh_lightoff '+bb['switchInput']);
            if(is_lightoff() === $light_input[0].checked) {  //checked==true开灯 false关灯
                $light_input[0].checked = !$light_input[0].checked;
            }
            lightoff_btn_css();

            let light_tip_text = $light_input[0].checked === true? '关灯': '开灯';
            $('#hhh_lightoff .tooltip').text(light_tip_text);
            if(bb_type.indexOf(BILI_2_X) !== -1) $('#hhh_lightoff').data('tip')['text'] = light_tip_text;
        }
        //关灯按钮初始化
        function lightoff_init() {
            //插入关灯按钮
            $(`${bb['danmakuSwitch']}:first`).clone().prependTo(`${bb['danmakuRoot']}:first`)[0].id = 'hhh_lightoff';
            $('#hhh_lightoff '+bb['switchInput'])[0].checked = true;
            if(bb_type !== BILI_2_X_V3) $(`#hhh_lightoff ${bb['switchDot']}`)[0].innerHTML = '灯';
            else{
                //开灯
                $('#hhh_lightoff').find('.bui-danmaku-switch-on svg').replaceWith(`
                    <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                    <path style="clip-rule:evenodd;fill-rule:evenodd" d="M 15.765 1.814 C 15.513 1.840 15.264 1.971 15.068 2.244 L 13.207 4.835 C 12.827 4.831 12.463 4.828 12.119 4.828 L 11.988 4.828 C 11.518 4.828 11.014 4.831 10.474 4.839 L 8.763 2.273 C 8.018 1.154 6.340 2.273 7.085
                    3.392 L 8.085 4.892 C 7.404 4.910 6.682 4.932 5.921 4.960 C 3.981 5.029 2.367 6.478 2.091 8.400 C 1.926 9.550 1.845 10.945 1.845 12.585 C 1.845 14.550 1.960 16.255 2.195 17.701 C 2.499 19.569 4.068 20.971 5.958 21.064 L 6.865 21.109 C 8.070 21.172 8.673 21.205 10.472
                    21.205 C 11.748 21.164 11.748 19.271 10.472 19.230 C 8.714 19.230 8.132 19.200 6.970 19.138 L 6.056 19.091 C 5.096 19.044 4.300 18.331 4.146 17.382 C 3.930 16.058 3.820 14.459 3.820 12.585 C 3.820 11.022 3.897 9.721 4.046 8.681 C 4.186 7.704 5.005 6.967 5.990 6.933 C
                    8.434 6.846 10.456 6.803 12.054 6.802 C 13.652 6.802 15.673 6.847 18.117 6.933 C 19.077 6.967 19.827 7.742 19.972 8.746 C 20.047 9.270 20.085 10.709 20.113 11.812 L 20.113 11.814 C 20.123 12.156 20.130 12.463 20.138 12.693 C 20.184 14.009 22.158 13.942 22.113 12.626 C
                    22.105 12.400 22.096 12.102 22.087 11.769 L 22.087 11.742 C 22.057 10.624 22.014 9.079 21.927 8.466 C 21.654 6.560 20.144 5.029 18.187 4.960 C 17.287 4.928 16.444 4.902 15.656 4.882 L 16.707 3.421 C 17.295 2.602 16.520 1.735 15.765 1.814 z M 8.896 8.152 C 8.896 9.808
                    8.883 10.962 8.855 11.613 C 8.831 12.260 8.747 12.892 8.605 13.513 C 8.466 14.134 8.271 14.693 8.017 15.189 C 7.764 15.682 7.456 16.112 7.095 16.480 C 7.359 16.756 7.695 17.191 8.105 17.783 C 8.838 16.784 9.358 15.814 9.667 14.871 C 10.122 15.390 10.560 15.912 10.980
                    16.441 L 12.052 15.396 C 11.413 14.729 10.733 14.076 10.011 13.439 C 10.067 13.104 10.114 12.726 10.152 12.302 C 10.850 11.691 11.511 11.083 12.136 10.478 L 11.126 9.562 C 10.911 9.845 10.622 10.200 10.261 10.630 C 10.289 9.891 10.302 9.065 10.302 8.152 L 8.896 8.152 z
                    M 11.751 8.625 L 11.751 9.947 L 14.052 9.947 L 14.052 15.357 C 14.052 15.915 13.792 16.195 13.271 16.195 C 12.872 16.195 12.387 16.176 11.814 16.136 C 11.971 16.575 12.099 17.059 12.203 17.585 A 1.939 1.750 0 0 1 13.539 17.101 A 1.939 1.750 0 0 1 14.625 17.402 C 14.708
                    17.370 14.808 17.345 14.871 17.304 C 15.103 17.160 15.277 16.953 15.392 16.683 C 15.507 16.414 15.564 16.082 15.564 15.691 L 15.564 9.947 L 17.458 9.947 L 17.458 8.625 L 11.751 8.625 z M 8.189 9.730 L 7.074 9.917 C 7.247 10.877 7.404 11.926 7.542 13.070 L 8.677 12.865 C 8.511 11.669 8.349 10.624 8.189 9.730 z "/>
                    <path fill-rule="evenodd" clip-rule="evenodd" d="M22.846 14.627a1 1 0 00-1.412.075l-5.091 5.703-2.216-2.275-.097-.086-.008-.005a1 1 0 00-1.322 1.493l2.963 3.041.093.083.007.005c.407.315 1 .27 1.354-.124l5.81-6.505.08-.102.005-.008a1 1 0 00-.166-1.295z" fill="#00AEEC"/>
                    </svg>`
                 );
                //关灯
                $('#hhh_lightoff').find('.bui-danmaku-switch-off svg').replaceWith(`
                    <svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                    <path style="clip-rule:evenodd;fill-rule:evenodd" d="M 15.765 1.814 C 15.514 1.840 15.264 1.971 15.068 2.244 L 13.207 4.835 C 12.826 4.831 12.464 4.828 12.119 4.828 L 11.988 4.828 C 11.518 4.828 11.014 4.831 10.474 4.839 L 8.765 2.273 C 8.020 1.154 6.340 2.273 7.085
                    3.392 L 8.085 4.890 L 8.083 4.890 C 7.402 4.909 6.680 4.933 5.919 4.960 C 3.979 5.030 2.367 6.478 2.091 8.400 C 1.926 9.549 1.845 10.943 1.845 12.583 C 1.845 14.548 1.961 16.253 2.197 17.699 C 2.500 19.567 4.068 20.970 5.958 21.064 C 7.861 21.158 9.276 21.205 11.472
                    21.205 C 12.748 21.164 12.748 19.271 11.472 19.230 C 9.666 19.234 7.860 19.188 6.056 19.091 C 5.096 19.043 4.300 18.331 4.146 17.382 C 3.931 16.058 3.820 14.459 3.820 12.585 C 3.820 11.022 3.896 9.721 4.046 8.681 C 4.186 7.704 5.004 6.968 5.990 6.933 C 8.434 6.847
                    10.456 6.802 12.054 6.802 C 13.652 6.803 15.673 6.846 18.117 6.933 C 19.076 6.966 19.829 7.742 19.972 8.746 C 20.048 9.270 20.085 10.709 20.113 11.812 L 20.113 11.814 C 20.122 12.156 20.130 12.465 20.138 12.695 C 20.184 14.011 22.159 13.942 22.113 12.626 C 22.105
                    12.400 22.097 12.102 22.087 11.769 L 22.087 11.742 C 22.057 10.624 22.015 9.079 21.927 8.466 C 21.655 6.559 20.145 5.029 18.187 4.960 C 17.288 4.928 16.444 4.902 15.656 4.882 L 16.705 3.421 C 17.293 2.603 16.520 1.736 15.765 1.814 z M 8.896 8.152 C 8.896 9.808 8.883
                    10.960 8.855 11.611 C 8.831 12.258 8.747 12.892 8.605 13.513 C 8.466 14.134 8.271 14.693 8.017 15.189 C 7.764 15.682 7.456 16.112 7.095 16.480 C 7.359 16.756 7.695 17.189 8.105 17.781 C 8.838 16.782 9.358 15.812 9.667 14.869 C 10.122 15.388 10.560 15.912 10.980 16.441
                    L 12.052 15.396 C 11.413 14.729 10.733 14.076 10.011 13.439 C 10.067 13.104 10.114 12.724 10.152 12.300 C 10.850 11.689 11.511 11.083 12.136 10.478 L 11.125 9.560 C 10.909 9.843 10.622 10.200 10.261 10.630 C 10.289 9.891 10.302 9.065 10.302 8.152 L 8.896 8.152 z
                    M 11.75 8.625 L 11.75 9.945 L 14.052 9.945 L 14.052 14.726 A 5.249 5.249 0 0 1 15.562 13.486 L 15.562 9.945 L 17.458 9.945 L 17.458 8.625 L 11.75 8.625 z M 8.189 9.728 L 7.074 9.916 C 7.247 10.875 7.404 11.926 7.542 13.070 L 8.677 12.863 C 8.511 11.667 8.349 10.622 8.189 9.728 z
                    M 18.062 14.062 C 12.729 14.062 12.729 22.062 18.062 22.062 C 23.395 22.062 23.395 14.062 18.062 14.062 z M 18.212 15.560 C 19.463 15.638 20.561 16.667 20.560 18.060 C 20.560 18.480 20.456 18.875 20.273 19.222 L 16.945 15.820 C 17.360 15.613 17.796 15.534 18.212 15.560 z
                    M 11.812 16.136 C 11.972 16.583 12.104 17.076 12.208 17.615 C 12.430 17.617 12.643 17.601 12.861 17.597 A 5.249 5.249 0 0 1 13.195 16.191 C 12.808 16.189 12.355 16.174 11.812 16.136 z M 15.843 16.902 L 19.169 20.300 C 18.825 20.471 18.445 20.561 18.060 20.560 C 16.182 20.561 14.974 18.567 15.843 16.902 z"/>
                    </svg>`
                 );
            }
            //css
            lightoff_btn_css();
            //add tips
            waitForTrue(()=> ($tip !== undefined && $('#hhh_lightoff').length === 1), () => {
                if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"flex"});
                $(bb['dmWrap']).css({"display":"block"});

                if(bb_type === BILI_2_X_V2) $('#hhh_lightoff').data('tip', {'text': '关灯', 'millisec':1, 'top':2, 'left':0, 'diff_full_top':-20});
                else if(bb_type === BILI_2_X_V3) $('#hhh_lightoff').data('tip', {'text': '关灯', 'millisec':1, 'top':-4, 'left':0, 'diff_full_top':-14});
                add_tip($tip, $('#hhh_lightoff'), {});

                $(bb['dmWrap']).css({"display":"none"});
                if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"none"});
            })
        }

        //模拟B站音量调节
        //2.X版本可以直接调用系统函数window.player.volume(),但不能直接使用H5Player.volume
        //3.X版本去掉了window.player.volume(),但H5Player.volume功能发生变动,基本等价于window.player.volume()
        function volume(v, is_show_hint=true){
            function volume_bar(v){  //未使用
                if(v === undefined) return;
                v = v<0? 0: v>1? 1: v;
                $('.bilibili-player-video-volume-num').text(Math.round(v*100));
                $('.bilibili-player-video-volumebar-wrp .bui-bar.bui-bar-normal')[0].style.transform = `scaleY(${v})`;
                $('.bilibili-player-video-volumebar-wrp .bui-thumb')[0].style.transform = `translateY(${-48*v}px)`;
                v === 0? $('.bilibili-player-video-btn.bilibili-player-video-btn-volume').addClass('video-state-volume-min'): $('.bilibili-player-video-btn.bilibili-player-video-btn-volume').removeClass('video-state-volume-min')
            }
            function volume_hint_bar(v){
                if(v === undefined) return;
                assert(typeof v === "number", '| volume err: v is not number')  //debug
                //v = v<0? 0: v>1? 1: v;
                v = +Math.max(Math.min(v,1),0).toFixed(3);
                var $volumeHintIcon = $(`#hhh_volumeHint ${bb['volumeHintIcon']}`);
                var volumeHintIconClassName = bb['volumeHintIcon'].substr(1);

                if(bb_type.indexOf(BILI_2_X) !== -1){
                    if(v <= 0) $volumeHintIcon.attr('class', `${volumeHintIconClassName} video-state-volume-min`);
                    else if(v >= 1) $volumeHintIcon.attr('class', `${volumeHintIconClassName} video-state-volume-max`);
                    else $volumeHintIcon.attr('class', volumeHintIconClassName);
                } else{
                    if(v <= 0){
                        $volumeHintIcon.find('.bpx-common-svg-icon:last').css('display','block');
                        $volumeHintIcon.find('.bpx-common-svg-icon:first').css('display','none');
                    } else{
                        $volumeHintIcon.find('.bpx-common-svg-icon:last').css('display','none');
                        $volumeHintIcon.find('.bpx-common-svg-icon:first').css('display','block');
                    }
                }

                if(v <= 0) showHint(this, '#hhh_volumeHint', '静音');
                else showHint(this, '#hhh_volumeHint', Math.round(v*100)+'%');
            }

            h5Player = ($(`${bb['video']} video`)[0] || $(`${bb['video']} bwp-video`)[0]);  // bug:调节清晰度会影响 h5Player 和window.player,需要重新赋值
            assert(typeof h5Player.volume === "number", '| volume err: h5Player.volume is not number')  //debug
            if(v === undefined) { /*log('v: '+h5Player.volume);*/ return +h5Player.volume;}
            v = +Math.max(Math.min(v,1),0).toFixed(3);
            assert(typeof v === "number", '| volume err: v is not number')  //debug
            //log('volume: '+v+'  '+h5Player);
            //v = v<0.01? 0: v>1? 1: v;  //0.01防止误差
            bb_type.indexOf(BILI_2_X) !== -1? window.player.volume(v): h5Player.volume = v;
            //h5Player.volume = v;
            if(is_show_hint === true) volume_hint_bar(+h5Player.volume);
            return +h5Player.volume;
        }

        //显示提示
        function showHint(parent, selector_str, text){
            $(bb['volumeHint']).css({"visibility":"visible"})
            $(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(isWheelVolume=ON, screenLeft=0.3, screenRight=0.7, delta=1, isPauseVolume=ON){
            $(bb['videoWrap']).off('mousewheel.hhh_volumeHint');
            if(!isWheelVolume) return;
            $(bb['videoWrap']).on('mousewheel.hhh_volumeHint', function(e){
                if(e.ctrlKey || e.altKey || e.shiftKey) return;
                //缺省屏幕百分比参数,默认0.3~0.7
                screenLeft = (screenLeft<0 || screenLeft>1)? 0.3: screenLeft;
                screenRight = (screenRight<0 || screenRight>1)? 0.7: screenRight;
                //缺省音量百分比,默认1
                delta = (delta<1 || delta>100)? 1: delta;

                //非暂停(可选) && 鼠标在屏幕指定位置时处理
                var pauseState = isPauseVolume || h5Player.paused === false;
                var Rect = $(bb['videoWrap'])[0].getBoundingClientRect();
                var offsetX = e.originalEvent.x - Rect.x;
                var inLimit = offsetX > Rect.width*screenLeft && offsetX < Rect.width*screenRight;

                if(is_fullscreen() || (pauseState && inLimit)) {
                    //阻止页面滚动 && 阻止冒泡
                    e.preventDefault();
                    e.stopPropagation();
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var v = volume();
                    if(wheelDelta >= 120) {  //向上滚动,减少音量
                        volume(+(v+(delta/100)).toFixed(3));  //+ string to number
                    } else if(wheelDelta <= -120) {  //向下滚动,增大音量
                        volume(+(v-(delta/100)).toFixed(3));
                    }
                }
            });
        }

        /*
         * 控制进度条
         * .bilibili-player-setting-opacity 透明度
         * .bilibili-player-setting-area 显示区域
         * .bilibili-player-setting-speedplus 弹幕速度 等
         * 利用系统mousedown事件
         * 0 ~ 100
         */
        function set_progress(selector_str, percent, limit_left, limit_right){
            function calc_bar_offset2(percent, bar_width, limit_left, limit_right){  //某种插值算法,未使用
                let p = +percent;
                p = p<limit_left? limit_left: p>limit_right? limit_right: p;
                //log(p+' - '+bar_width+' - '+(limit_right-limit_left));
                let limits = limit_right - limit_left;
                let quo = Math.floor((p-limit_left)*bar_width/limits);
                let rem = (p-limit_left)*bar_width%limits;
                //log(quo+'****'+rem);
                return (bb_type === BILI_3_X)? Math.round((p-limit_left)/limits*bar_width): (rem>=(limits/2)? quo+1: quo);  //百分比对应进度条位置
            }

            function calc_bar_offset(percent, bar_width, limit_left, limit_right){
                let p = Math.max(Math.min(+percent, limit_right), limit_left);
                //log(p+' - '+bar_width+' - '+(limit_right-limit_left));
                let limits = limit_right - limit_left;
                let bar_offset = (p-limit_left) / limits * bar_width;
                return Math.round(bar_offset);  //百分比对应进度条位置
            }

            let selector = document.querySelector(selector_str);
            let e1 = new MouseEvent('mousedown'), e2 = new MouseEvent('mouseup');

            if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"flex"});
            $(bb['dmWrap']).css({"display":"block"});

            let selector_rect = selector.getClientRects();
            //log(selector.getBoundingClientRect()[0]+' - '+selector_rect[0]);
            let bar_offset = calc_bar_offset(percent, $(`${selector_str} ${bb['progressWrap']}`).innerWidth(), limit_left, limit_right);
            //log('wrapWIdth: '+ calc_bar_len(percent, $(`${selector_str} ${bb['progressWrap']}`).innerWidth(), limit_left, limit_right));
            for(let i=0;i<10;i++){
                let dest_per = Math.max(Math.min(+percent, limit_right), limit_left);
                let clientX = selector_rect[0].left + bar_offset;
                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);
                let curr_per = +$(`${selector_str} ${bb['progressVal']}`).text().slice(0,-1);
                //log(curr_per+' - '+dest_per);
                if(curr_per !== dest_per){
                    curr_per < dest_per ? ++bar_offset : --bar_offset;
                    //log(bar_offset);
                }else{
                    break;
                }
            }

            $(bb['dmWrap']).css({"display":"none"});
            if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"none"});

            //激活设置,记忆进度条位置
            if(bb_type === BILI_3_X){
                $(bb['dm'])[0].dispatchEvent( new MouseEvent('mouseleave') );  //3.X
            }else{
                $(bb['dm'])[0].dispatchEvent( new MouseEvent('mouseout') );  //2.X
            }

            return $(`${selector_str} ${bb['progressVal']}`).text();
        }

        /*
         * 调节弹幕设置进度条
         * 利用系统mousedown事件
         * '正数': right,  '负数': left,  -100 ~ +100
         */
        function adjust_progress(selector_str, inc_percent, limit_left, limit_right){
            var curr_percent = Number($(`${selector_str} ${bb['progressVal']}`).text().slice(0,-1));
            return set_progress(selector_str, curr_percent + inc_percent, limit_left, limit_right);
        }

        //滚轮调节弹幕透明度(ctrl),参数表示滚动一下增加的透明度百分比
        function wheel_opacity(status, delta=5){
            $(bb['videoWrap']).off('mousewheel.hhh_opacity');
            if(status === OFF) return;
            $(bb['videoWrap']).on('mousewheel.hhh_opacity', function(e){
                if(e.ctrlKey === true) {
                    //阻止页面滚动 && 阻止冒泡
                    e.preventDefault();
                    e.stopPropagation();
                    //缺省透明度百分比,默认5
                    delta = (delta<1 || delta>100)? 5: delta;
                    var wheelDelta = e.originalEvent.wheelDelta;
                    var opacity;
                    if(wheelDelta >= 120) {  //向上滚动,增大透明度
                        opacity = adjust_progress(bb['settingOpacity'], delta, 10, 100);
                    } else if(wheelDelta <= -120) {  //向下滚动,减少透明度
                        opacity = adjust_progress(bb['settingOpacity'], -delta, 10, 100);
                    }
                    if(opacity !== undefined) showHint(document, '#hhh_opacityHint', '透 '+opacity);
                }
            });
        }

/*        /  \
       |  |
       \  /
clip-path: polygon(40% 0%, 25% 30%, 25% 70%, 40% 100%, 0% 100%, 0% 0%,60% 0%, 75% 30%, 75% 70%, 60% 100%, 100% 100%, 100% 0%);

        <div style="width:200px;height:200px;background:red;clip-path: url(#myClip);">

	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	<div>11111111111111111111111</div>
	</div>

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      <circle cx="100" cy="100" r="40"/>
      <circle cx="60" cy="60" r="40"/>
    </clipPath>
  </defs>
</svg>

        $('.bilibili-player-context-menu-container.active li:last').mouseenter(function(){
    let hotkey_class = '.bilibili-player-hotkey-panel-container'.substr(1);
    $('#hhh_hotkey_panel').clone(true,true).replaceAll($(`.${hotkey_class}:last`)).attr({'id': '', 'class': hotkey_class, 'style': ''});
    let $hotkey = $('.bilibili-player-hotkey-panel-container').addClass('active').css('z-index', $('.bilibili-player-video-control-wrap').css('z-index'));
}).mouseleave(function(){
    $('.bilibili-player-hotkey-panel-container').removeClass('active').css('display', 'none');
})

BV to AV
        // 作者:mcfx
        // 链接:https://www.zhihu.com/question/381784377/answer/1099438784
        // 来源:知乎
        // 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
        function bv2av() {
            const bv = document.getElementById('bv').value;
            document.getElementById('av').value = dec(bv);
        }

        function av2bv() {
            const av = +document.getElementById('av').value;
            document.getElementById('bv').value = enc(av);
        }

        const table = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF'
        const tr = {}
        for (let i = 0; i < 58; i++)
            tr[table[i]] = i
        const s = [11, 10, 3, 8, 4, 6]
        const xor = 177451812
        const add = 8728348608

        function dec(x) {
            let r = 0
            for (let i = 0; i < 6; i++) {
                r += tr[x[s[i]]] * 58 ** i
            }
            return (r - add) ^ xor
        }
        function enc(x) {
            x = (x ^ xor) + add
            r = 'BV1  4 1 7  '.split('')
            for (let i = 0; i < 6; i++) {
                r[s[i]] = table[parseInt(x / 58 ** i) % 58]
            }
            return r.join('')
        }

        // console.log(dec('BV17x411w7KC'))
        // console.log(dec('BV1Q541167Qg'))
        // console.log(dec('BV1mK4y1C7Bz'))
        // console.log(enc(170001))
        // console.log(enc(455017605))
        // console.log(enc(882584971))
        // console.log('----------------------------');
        // console.log(1, enc(1))
        // console.log(93761707, dec(enc(93761707)))
        // console.log('BV1xE411x7Mn', enc(dec('BV1xE411x7Mn')))
        // console.log(add === 100618342136696320, add); */

        //自定义快捷键说明页面
        function add_custom_hotkey(hotkey_panel_class, hotkey, is_append) {
            var $hotkey_panel = $(`.${hotkey_panel_class}`);
            var $hotkey_item  = $hotkey_panel.find(`.${hotkey_panel_class}-item:first`);
            var key_name = bb_type.indexOf(BILI_2_X) !== -1 ? 'key' : 'name';
            if(is_append === false) $hotkey_panel.empty();
            for (let [key, { value, text }] of Object.entries(hotkey)) {
                $hotkey_item.clone().appendTo($hotkey_panel);
                let $hotkey_key = $hotkey_panel.find(`.${hotkey_panel_class}-${key_name}:last`);
                $hotkey_key.text(value);
                $hotkey_key.next().text(text);
            }
        }

        //添加右键菜单自定义快捷键说明2.X
        function add_custom_hotkey_menu_2_X(custom_hotkey) {
            //主class名,去掉"."
            let hotkey_panel_class = 'bilibili-player-hotkey-panel',
                is_init = false;

            //设置右键 & 快捷键菜单
            (function add_menu(){
                $('#bilibiliPlayer')[0].addEventListener('DOMSubtreeModified', function(e) {
                    //typeof e.target.className === 'string' && e.target.className !== '' && log(e.target.className);
                    let $target = $(e.target);
                    if($target.hasClass('context-line context-menu-function hover') && $('.bilibili-player-hotkey-panel').length === 1){
                        if(is_init === false){
                            //log('-------添加快捷键菜单--------');
                            is_init = true;
                            let $last_item = $('.bilibili-player-hotkey-panel').find('.bilibili-player-hotkey-panel-item:last');
                            $last_item.attr('id', 'hhh_last_system_hotkey_panel_item');
                            add_custom_hotkey(hotkey_panel_class, custom_hotkey, true);
                        }else if($target[0].id !== '__sizzle__'){  //过滤掉第一个懒加载
                            let $last_system_itme = $('#hhh_last_system_hotkey_panel_item');
                            //log($target.find('a').text());
                            if($target.find('a').text() === '快捷键说明'){
                                    //log('--------显示快捷键说明-------');
                                    $last_system_itme.prevAll().css('display','block');
                                    $last_system_itme.css('display','block');
                                    $last_system_itme.nextAll().css('display','none');
                            }else if($target.find('a').text() === '快捷键说明(bilibili关灯)'){
                                    //log('--------显示快捷键说明(bilibili关灯)-------');
                                    $last_system_itme.prevAll().css('display','none');
                                    $last_system_itme.css('display','none');
                                    $last_system_itme.nextAll().css('display','block');
                            }
                            let wheelEvent = new WheelEvent('mousewheel', { deltaY: -10000, deltaMode: 0 });  //打开时回到最上
                            $('.bilibili-player-hotkey-panel-wrap')[0].dispatchEvent(wheelEvent);
                            $('.bilibili-player-hotkey-panel-wrap').find('.bscroll-vertical-scrollbar')[0].style.cssText+=";background:#f1f1f1!important";  //默认滚动条对比度不明显,浅化背景颜色,增强对比度
                        }
                    } else if($target.hasClass('bilibili-player-context-menu-container black bilibili-player-context-menu-origin') &&  $target[0].id === '') {  //还有一个id = __sizzle__
                        this.removeEventListener('DOMSubtreeModified', arguments.callee);
                        //log('--------添加右键菜单-------');
                        let $li_sys_hotkey = $target.find('a:contains("快捷键说明"):first').parent();  //返回li,XXX: 此时contains("快捷键说明")多于一个
                        let $a_hhh_hotkey = $target.find('a:contains("快捷键说明(bilibili关灯)")');
                        var $li_hhh_hotkey = ($a_hhh_hotkey.length && $a_hhh_hotkey.parent()) || $li_sys_hotkey.clone(false, false).insertAfter($li_sys_hotkey).css('display', '').find('a').text('快捷键说明(bilibili关灯)');  //插入自定义快捷键

                        add_menu();
                    }
                });
            })();
        }

        //添加右键菜单自定义快捷键说明3.X
        function add_custom_hotkey_menu_3_X(custom_hotkey) {
            //主class名,去掉"."
            let hotkey_panel_class = 'bpx-player-hotkey-panel-content';

            //监听右键菜单,生成自定义快捷键说明页面,只执行一次
            (function set_custom_hotkey(){
                $('.bpx-player-container')[0].addEventListener('DOMNodeInserted', function(e) {
                    //typeof e.target.className === 'string' && e.target.className !== '' && log(e.target.className);
                    let $target = $(e.target);
                    if($target.hasClass('bpx-player-hotkey-panel')){
                        //log('-------添加快捷键菜单--------');
                        let $last_item = $target.find('.bpx-player-hotkey-panel-content-item:last');
                        $last_item.attr('id', 'hhh_last_system_hotkey_panel_item');
                        add_custom_hotkey(hotkey_panel_class, custom_hotkey, true);
                    }
                });
            })();

            //右键菜单弹出时添加项
            (function add_menu(){
                $('.bpx-player-container')[0].addEventListener('DOMSubtreeModified', function(e) {
                    //typeof e.target.className === 'string' && e.target.className !== '' && log(e.target.className);
                    let $target = $(e.target);
                    if($target.hasClass('bpx-player-contextmenu bpx-player-black') && $target[0].childNodes.length !== 0) {
                        this.removeEventListener('DOMSubtreeModified', arguments.callee);
                        //log('--------添加右键菜单-------');
                        let $li_sys_hotkey = $target.find('li:contains("快捷键说明"):first');
                        var $li_hhh_hotkey = $li_sys_hotkey.clone(false, false).insertAfter($li_sys_hotkey).text('快捷键说明(bilibili关灯)');  //插入自定义快捷键

                        let $last_system_itme = $('#hhh_last_system_hotkey_panel_item');
                        //log('--------显示快捷键说明-------');
                        $li_sys_hotkey.mousedown(function(){
                            $last_system_itme.prevAll().css('display','block');
                            $last_system_itme.css('display','block');
                            $last_system_itme.nextAll().css('display','none');
                        });
                        //log('--------显示快捷键说明(bilibili关灯)-------');
                        $li_hhh_hotkey.mousedown(function(){
                            $last_system_itme.prevAll().css('display','none');
                            $last_system_itme.css('display','none');
                            $last_system_itme.nextAll().css('display','block');
                        });
                        let wheelEvent = new WheelEvent('mousewheel', { deltaY: -10000, deltaMode: 0 });  //打开时回到最上
                        $('.bpx-player-hotkey-panel-area')[0].dispatchEvent(wheelEvent);

                        add_menu();
                    }
                });
            })();

            //模拟右键菜单消息,激活菜单
            let evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
            $(bb['videoWrap'])[0].dispatchEvent(evt);

            //模拟点击菜单,激活热键菜单DOM
            evt = new MouseEvent('mousedown',{ bubbles:true });
            $(`.bpx-player-contextmenu.bpx-player-black li:contains("快捷键说明")`)[0].dispatchEvent(evt);

            //关闭热键菜单
            $('.bpx-player-hotkey-panel-close').click();
        }

/*         //自定义快捷键说明页面
        function set_custom_hotkey2($hotkey, sub_class, hotkey, is_append) {
            var $hotkey_panel = bb_type.indexOf(BILI_2_X) !== -1 ? $hotkey.find(`.${sub_class}:first`) : $hotkey.find(`.${sub_class}:first`);
            var $hotkey_item  = $hotkey.find(`.${sub_class}-item:first`);
            var key_name = bb_type.indexOf(BILI_2_X) !== -1 ? 'key' : 'name';
            if(is_append === false) $hotkey_panel.empty();
            for (let [key, { value, text }] of Object.entries(hotkey)) {
                $hotkey_item.clone().appendTo($hotkey_panel);
                let $hotkey_key = $hotkey_panel.find(`.${sub_class}-${key_name}:last`);
                $hotkey_key.text(value);;
                $hotkey_key.next().text(text).width(180);  // 3.X 默认宽度窄了
            }
        }
        //添加右键菜单自定义快捷键说明3.X2
        function add_custom_hotkey_menu_3_X2(custom_hotkey) {
            //主class名,去掉"."
            var player_hotkey_panel_class = 'bpx-player-hotkey-panel';

            //监听右键菜单,生成自定义快捷键说明页面,只执行一次
            (function add_custom_hotkey(){
                //$(bb['videoWrap'])[0].addEventListener('DOMNodeInserted', function(e) {
                $('.bpx-player-container')[0].addEventListener('DOMNodeInserted', function(e) {

                    let $target = $(e.target);
                    if($target.hasClass(player_hotkey_panel_class)) {
                        this.removeEventListener('DOMNodeInserted', arguments.callee);

                        //var $hotkey = $target.css('display', 'none');
                        var $hotkey = $target;
                        $hotkey.clone(true,true).insertBefore($hotkey).attr({'class': '','id': 'sys_hotkey_panel'}).css('display', 'none')
                                                                      .find(`.${player_hotkey_panel_class}-area`).css('max-height', '600px');  //bilibili自己的BUG,由于max-height限制,显示不全
                        $hotkey.clone(true,true).insertBefore($hotkey).attr({'class': '','id': 'hhh_hotkey_panel'}).css('display', 'none')
                                                                      .find(`.${player_hotkey_panel_class}-area`).css('max-height', '600px');

                        $('#sys_hotkey_panel .bpx-player-hotkey-panel-close').click(function(){ $(this).parent().parent().css('display', 'none') });  //jquery问题,clone失败,自定义关闭按钮事件
                        $('#hhh_hotkey_panel .bpx-player-hotkey-panel-close').click(function(){ $(this).parent().parent().css('display', 'none') });  //jquery问题,clone失败,自定义关闭按钮事件

                        //自定义快捷键说明页面
                        set_custom_hotkey2($('#hhh_hotkey_panel'), `${player_hotkey_panel_class}-content`, custom_hotkey, false);
                    }
                });
            })();

            //右键菜单弹出时添加项
            (function add_menu(){
                $('#bilibili-player')[0].addEventListener('DOMSubtreeModified', function(e) {
                    let $target = $(e.target);
                    if($target.hasClass('bpx-player-contextmenu bpx-player-black') &&  $target[0].id === '') {  //还有一个id = __sizzle__
                        this.removeEventListener('DOMSubtreeModified', arguments.callee);

                        if($target.find('li:contains("快捷键说明"):first').length === 1) {
                            var $li_sys_hotkey = $target.find('li:contains("快捷键说明"):first');  //XXX: 此时contains("快捷键说明")多于一个
                            var $li_hhh_hotkey = $li_sys_hotkey.clone(false, false).insertAfter($li_sys_hotkey).css('display', '').text('快捷键说明(bilibili关灯)');

                            $li_sys_hotkey.mousedown(function(){
                                $('#sys_hotkey_panel').clone(true,true).replaceAll($(`.${player_hotkey_panel_class}:last`)).attr({'id': '', 'class': player_hotkey_panel_class, 'style': ''});
                            });
                            $li_hhh_hotkey.mousedown(function(){
                                $('#hhh_hotkey_panel').clone(true,true).replaceAll($(`.${player_hotkey_panel_class}:last`)).attr({'id': '', 'class': player_hotkey_panel_class, 'style': ''});
                            });
                        }

                        add_menu();
                    }
                });
            })();

            //模拟右键菜单消息,激活菜单
            let evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
            $(bb['videoWrap'])[0].dispatchEvent(evt);

            //模拟点击菜单,激活热键菜单DOM
            evt = new MouseEvent('mousedown',{ bubbles:true });
            $(`.bpx-player-contextmenu.bpx-player-black li:contains("快捷键说明")`)[0].dispatchEvent(evt);

            //关闭热键菜单
            $('.bpx-player-hotkey-panel-close').click();
        } */

        //添加右键菜单自定义快捷键说明
        function add_custom_hotkey_menu(hotKeyMenu) {
            if(bb_type.indexOf(BILI_2_X) !== -1) add_custom_hotkey_menu_2_X(hotKeyMenu);
            else add_custom_hotkey_menu_3_X(hotKeyMenu);
        }

        //取得版本号-未使用
        //function get_ver() {
        //    if(bb_type.indexOf(BILI_2_X) !== -1) ver = bili_player.getVersion().version;
        //    else ver = $('.bpx-common-opacity-60').text().split('-')[0];
        //}

        //取得视频FPS(Frames Per Second)和版本
        function get_video_fps_ver() {
            $(bb['videoWrap'])[0].addEventListener('DOMNodeInserted', function(e) {
                //插入info面板时截取fps值
                if($(e.target).hasClass(bb['DOMNodeInsertedVideoInfoShow'].substr(1))) {
                    this.removeEventListener('DOMNodeInserted', arguments.callee);

                    let $video_info_close = $(bb['videoInfoClose']);
                    $video_info_close.click();  //模拟关闭统计信息面板,2.X版本一次即可关掉
                    $video_info_close.click();  //3.X版本执行两次才能关掉面板,保险起见3次
                    $video_info_close.click();  //估计是点击事件开始太快,系统未能处理,也可能3.X测试版自己的问题

                    //text中取得fps值
                    var get_title_text = function(title) { return $(bb['videoInfoContainer']).find(`.info-title:contains("${title}")`).next().text(); }
                    fps = Number(get_title_text('Resolution').match(/\d+\.\d+/)) || Number(get_title_text('FPS')) || 30;
                }
            })

            //模拟右键菜单消息,激活菜单DOM
            let evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
            $(bb['videoContextMenu'])[0].dispatchEvent(evt);

            //模拟点击菜单,激活热键菜单DOM,版本号
            if(bb_type.indexOf(BILI_2_X) !== -1){
                let evt = new MouseEvent('click',{ bubbles:true });
                $(`${bb['playerContextMenu']} a:contains("视频统计信息")`)[0].dispatchEvent(evt);
                ver = $(`${bb['playerContextMenu']} a:contains("更新历史")`).text().split(' ')[1].split('-')[0];
            }
            else if(bb_type === BILI_3_X) {
                let evt = new MouseEvent('mousedown',{ bubbles:true });
                $(`${bb['playerContextMenu']} li:contains("视频统计信息")`)[0].dispatchEvent(evt);
                ver = $(`${bb['playerContextMenu']} li:contains("更新历史")`).text().match(/\S+/g)[1].split('-')[0];
            }
        }

        //笨办法,激活系统音量设置,复制volumeHint DOM
        function pick_volume_hint(){
            var original_volume = h5Player.volume;
            //监视提取提示DOM
            $(bb['videoWrap'])[0].addEventListener('DOMNodeInserted', function(e) {
                if($(e.target).hasClass(bb['volumeHint'].substr(1))) {
                    this.removeEventListener('DOMNodeInserted', arguments.callee);

                    volume(original_volume);  //模拟鼠标拖动无法按1%精确控制音量,系统自身限制或者说bug

                    //添加 volumeHint wordsHint opacityHint DOM
                    $(bb['volumeHint']).clone().appendTo(bb['videoWrap']).attr('id','hhh_volumeHint');

                    $('#hhh_volumeHint').clone().appendTo(bb['videoWrap']).attr('id','hhh_wordsHint').css({'opacity': 0, 'display': 'none'}).find(bb['volumeHintIcon']).remove();
                    $('#hhh_wordsHint').clone().appendTo(bb['videoWrap']).attr('id','hhh_opacityHint');

                    if(bb_type.indexOf(BILI_2_X) !== -1){
                        $('#hhh_wordsHint').css({'width':'auto','margin-left':'0px','padding-left':'8px','padding-right':'15px','transform':'translate(-50%)'})
                                           .find(bb['volumeHintText']).css({'width': 'auto', 'padding-left': '10px'});
                        $('#hhh_opacityHint').find(bb['volumeHintText']).css({'padding-right': '6px'});
                    }
                    else{
                        $('#hhh_wordsHint, #hhh_opacityHint').find(bb['volumeHintText']).css({'padding': '0 10px'});
                    }

                    //隐藏提示
                    $(bb['volumeHint']).css({"visibility":"hidden"});
                }
            });
            //激活系统音量设置,复制volumeHint DOM
            let evt = new KeyboardEvent('keydown', { keyCode:keycode['up'] });
            window.dispatchEvent(evt);
        }

        //快进时显示醒目进度条
        function dynamicProgress(dynamicHeight, staticHeight){
            if(bb_type.indexOf(BILI_2_X) !== -1) {
                if (1||$('.bilibili-player-area').hasClass('progress-shadow-show') === true) {
                    $('.bilibili-player-video-progress-shadow .bui-track-video-progress').css('cssText', `height:${dynamicHeight}px !important`);
                    clearTimeout(document.showVideoProgress);
                    document.showVideoProgress = window.setTimeout((function() { $('.bilibili-player-video-progress-shadow .bui-track-video-progress').css('cssText', `height:${staticHeight}px !important`); }), 2000);
                }
            } else {
                if(1||$('.bpx-player-container').hasClass('bpx-state-no-cursor') === true) {
                    $('.squirtle-progress-buffer').css({'height': `${dynamicHeight/2}px`});
                    $('.squirtle-progress-timeline').css({'height': `${dynamicHeight/2}px`});
                    $('.squirtle-progress-totalline').css({'height': `${dynamicHeight/2}px`});
                    clearTimeout(document.showVideoProgress);
                    document.showVideoProgress = window.setTimeout((function() {
                        $('.squirtle-progress-buffer').css({'height': `${staticHeight}px`});
                        $('.squirtle-progress-timeline').css({'height': `${staticHeight}px`});
                        $('.squirtle-progress-totalline').css({'height': `${staticHeight}px`});
                    }), 2000);
                }
            }
        }

        //修复选择历史弹幕时弹幕填装信息丢失问题
        function fix_danmaku_info() {
            if(bb_type.indexOf(BILI_2_X) !== -1) {
                //log($('.danmaku-box').length);
                $('.danmaku-box')[0].addEventListener('DOMSubtreeModified', function(e) {
                    if($(e.target).hasClass('player-auxiliary-danmaku-list bpui-component bpui-undefined bpui-selectable') && $('.bilibili-player-video-info').hasClass('bilibili-player-hide-dm')) {
                        $('.bilibili-player-video-info').removeClass('bilibili-player-hide-dm');
                        //得到弹幕数
                        let danmaku_number = $('.player-auxiliary-danmaku-contaner .player-auxiliary-danmaku-list').height()/$('.danmaku-info-row:first').height();
                        $('.bilibili-player-video-info-danmaku-number').text(danmaku_number);
                    }
                });
            } else {
                $('.bpx-player-video-info')[0].addEventListener('DOMSubtreeModified', function(e) {
                    if($(e.target).hasClass('bpx-player-video-info-dm') && $('.bpx-player-video-info').hasClass('bpx-player-hide-dm')) {
                        $('.bpx-player-video-info').removeClass('bpx-player-hide-dm');
                    }
                });
            }
        }

        //初始化自定义设置 节点 事件 tips
        //setting - wrap - box | wrap - move - item
        function init_setting(run_default_setting_flag){
            var $DSet = $(bb['dm']);
            var $wrap = $DSet.find('.bui-panel-wrap');
            var $move = $DSet.find('.bui-panel-move');
            var $item_0 = $DSet.find('.bui-panel-item:eq(0)');
            var $item_1 = $DSet.find('.bui-panel-item:eq(1)');
            var $item_2;
            var old_width = $item_0.width() + $item_1.width();
            var item_0_height = $item_0.height() + 36;
            var item_2_width = $item_0.width() + 20;
            var item_2_height = 452+22*2;

            //
            if($DSet.length!=1 || $wrap.length!=1 || $move.length!=1) log('init_setting失败');
            if($item_0.length!=1 || $item_1.length!=1) log('init_setting失败2');

            /*-----------------------------------
             * 初始化
             *----------------------------------*/
            //初始化【$item_0】高度
            $item_0.css('height', item_0_height);
            $item_0[0].hhh_new_height = item_0_height;

            //初始化【$move】宽度
            $DSet.find('.bui-panel-move').css('width', old_width + item_2_width);

            /*-----------------------------------
             * 复制所需节点
             *----------------------------------*/
            //复制【item_0】【高级设置】To【自定义设置】
            $(bb['dmLeftMore']).clone().appendTo(bb['dmLeft']).attr('id', 'hhh_more')
                                                              .css('top', '20px')
                                                              .find(bb['dmLeftMoreText']).text('自定义设置');
            //复制【item_1】 To 【item_2】
            $item_2 = $item_1.clone().appendTo($move).attr('id', 'hhh_item')
                                                     .css({'width':item_2_width, 'height':item_2_height})
                                                     .removeClass('bui-panel-item-active')
                                                     .find('div *').remove().end();
            //复制【分割线】模板
            var $separator = $item_1.find(`${bb['dmRightSeparator']}:first`).clone();

            //复制【$title $hotkey父节点】模板
            var $title_div = $item_0.find(bb['dmLeftBlock']).clone().attr('id', 'hhh_title_div')
                                                                    //.css({'display': 'flex', 'flex-direction': 'column'})
                                                                    .empty().css({'margin-top': 6, 'margin-bottom': 2, 'height': 32+0});

            //复制【title】模板
            var $title = $item_0.find(bb['dmLeftBlockTitle']).clone().css({'color': '#12b3e8'})
                                                                     .css({'display': 'inline-flex', 'line-height': '32px'})
                                                                     .text('bilibili关灯自定义设置');
            //复制【快捷键说明】模板
            var $hotkey = $item_1.find(bb['dmRightMore']).clone().attr('id', 'hhh_item_2_hotkey')
                                                                 .css({'display': 'inline-flex', 'float': 'right'})
                                                                 .find('span:first').remove().end()
                                                                 .find(bb['dmRightMoreText']).text('快捷键说明(点击切换)').end();
            //
            var $div = $('<div></div>');
            var $middle_div = $div.clone().css({'display':'flex', 'justify-content':'space-between'});
            //复制【封面】模板
            var $cover = $item_1.find(bb['dmRightMore']).clone().attr('id', 'hhh_item_2_cover')
                                                                 //.css({'display': 'inline-flex', 'float': 'right', 'flex-direction': 'row-reverse'})
                                                                 //.css({'float': 'right'})
                                                                 .find('span:first').remove().end()
                                                                 .find(bb['dmRightMoreText']).text('显示封面(点击切换)').end();
            //复制【input-checkbox父节点】模板
            var $input_div = $item_0.find(bb['dmLeftBlock']).clone().attr('id', 'hhh_input_div')
                                                                    .empty().css({'margin-top': 4, 'margin-bottom': 2})
                                                                    //.css('background', 'blue')
                                                                    //.css('width', 200)
                                                                    ;
            //复制【更多其他】模板
            var $more_div = $item_0.find(bb['dmLeftBlock']).clone().attr('id', 'hhh_input_div2')
                                                                    .empty().css({'margin-top': 4, 'margin-bottom': 2})
                                                                    //.css('background', 'red')
                                                                    //.css('width', 100).css('height', 100)
                                                                    ;

            //复制【input-checkbox】模板
            var $input = $item_0.find(bb['dmLeftFlagTitle']).clone().css({'display': 'flex', 'margin-top': '6px'})  //inline-flex
                                                                   .find('input').removeAttr('aria-label').prop('checked', false).end()
                                                                   .find('.bui-checkbox-name').text('bilibili关灯').end();
            //复制【恢复默认设置】模板
            var $reset = $item_1.find(bb['dmRightReset']).clone().css({'margin-top': 6, 'margin-bottom': 6});

            //复制【返回】模板
            var $reback = $item_1.find(bb['dmRightMore']).clone().attr('id', 'hhh_item_2_more')
                                                                 .css({'margin-top': 2})
                                                                 .find(bb['dmRightMoreText'])
                                                                 .text('返回').end();
            /*-----------------------------------
             * 添加节点
             *----------------------------------*/
            let $item_2_div = $item_2.children(':first');

            /*-----------------------------------
             * 上部div
             *----------------------------------*/
            //添加title hotkey
            $title_div.appendTo($item_2_div);
            $title.clone().appendTo($title_div);
            $hotkey.clone().appendTo($($title_div));
            //添加分割线
            $separator.clone().appendTo($item_2_div);

            /*-----------------------------------
             * 中部div
             *----------------------------------*/
            $middle_div.appendTo($item_2_div);
            $input_div.appendTo($middle_div);
            $more_div.appendTo($middle_div);
            //添加 & 初始化【checkbox】
            for (let [key, { text, status, args, show }] of Object.entries(config.sets)) {
                if(show === OFF) continue;
                $input.clone().appendTo($input_div).attr('id', key)
                                                   .find('input').prop('checked', status).end()
                                                   .find('.bui-checkbox-name').text(text);

                if(key === 'volumeControlWhenNonFullScreen')
                    config.setCheckboxSettingTips('volumeControlWhenNonFullScreen', `在屏幕中间${Math.round((args.screenRight-args.screenLeft)*100)}%范围内调节,步幅${args.delta}%`);
            }

            //添加恢复默认设置
            $reset.clone().appendTo($input_div);
            //添加封面
            $cover.appendTo($more_div);

            /*-----------------------------------
             * 下部div
             *----------------------------------*/
            //添加分割线
            $separator.clone().appendTo($item_2_div);
            //添加返回
            $reback.clone().appendTo($item_2_div);

            /*-----------------------------------
             * 添加事件等
             *----------------------------------*/
            //重设置【设置按钮】
            // $DSet.mouseenter(function(){
            //     $wrap.css('height', $DSet.find('.bui-panel-item-active').css('height'));
            // })

            //重设置【item_0 - 自定义设置】
            $('#hhh_more').click(function(){
                $wrap.css({'height': $item_2.css('height'), 'width': $item_2.css('width')});
                $move.css('transform', `translateX(-${old_width}px)`);
                $DSet.find('.bui-panel-item-active').removeClass('bui-panel-item-active');
                $item_2.addClass('bui-panel-item-active');
            })

            //重设置【item_1 - 更多弹幕设置】
            $item_1.find(bb['dmRightMore']).click(function(){
                $item_0.css('height', item_0_height);  //会改变item_0长度
                $wrap.css({'height': $item_0.css('height'), 'width': $item_0.css('width')});
            })

            //重设置【item_2 - 返回】
            $item_2.find('#hhh_item_2_more').click(function(){
                $wrap.css({'height': $item_0.css('height'), 'width': $item_0.css('width')});
                $move.css('transform', 'translateX(0px)');
                $DSet.find('.bui-panel-item-active').removeClass('bui-panel-item-active');
                $item_0.addClass('bui-panel-item-active');
            })

            //重设置【item_2 - 封面】
            $item_2.find('#hhh_item_2_cover').click(function(){
                if($('#hhh_img').length === 1){
                    let $hhh_img = $('#hhh_img');
                    //let width = $(bb['video']).width()*0.9;
                    //$('#hhh_img').css('width', width);
                    $hhh_img.css('display') === 'none'? $hhh_img.css('display', 'flex'): $hhh_img.css('display', 'none');
                } else {
                    let $img = $(`<img style="cursor:pointer" src="${$(bb['coverImg']).attr('content').replace('http:','https:')}" />`);
                    let $d = $div.clone().attr('id', 'hhh_img')
                                         .css({position: 'absolute', top:'50%', left:'50%', transform: 'translate(-50%,-50%)'})
                                         .css({'z-index':`${$(bb['playTipWrap']).css('z-index')}`})
                                         .css({'display':'flex'})
                                         //.css('width',width)
                                         .css({'align-items':'center','justify-content':'center'})
                                         .appendTo($(bb['videoWrap']));
                    $img.css({width:'100%', height:'auto'}).appendTo($d);
                    //重设置【item_2 - 封面 - IMG】
                    $('#hhh_img').click(function(){
                        $(this).css('display','none');
                        window.open($(bb['coverImg']).attr('content').replace('http:','https:'));
                    })
                    //let width = $(bb['video']).width()*0.9;
                    //log(width);
                    //if($img.width() > width) $('#hhh_img').css('width', 0);
                    //log($('#hhh_img').width());
                    //log($img.width());
                }
            })

            //重设置【item_2 - 快捷键说明】
            let set_hotkey_panel_close = false;
            $item_2.find('#hhh_item_2_hotkey').click(function(){
                let is_active = bb_type.indexOf(BILI_2_X) !== -1 ? $(bb['hotkeyPanel']).hasClass('active') : $(bb['hotkeyPanel']).css('display') !== 'none';
                //2.X和3.X不一样?我来让你一样!
                if(is_active === false){
                    let evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
                    $(bb['videoWrap'])[0].dispatchEvent(evt);
                    evt = bb_type.indexOf(BILI_2_X) !== -1? new MouseEvent('click', { bubbles:true }): new MouseEvent('mousedown', { bubbles:true });
                    let node = bb_type.indexOf(BILI_2_X) !== -1? 'a': 'li';
                    $(bb['playerContextMenu']).find(`${node}:contains("快捷键说明(bilibili关灯)")`)[0].dispatchEvent(evt);
                    //$(bb['playerContextMenu']).find(`li:contains("快捷键说明(bilibili关灯)")`).mousedown();

                    let $hotkey = $(bb['hotkeyPanel']);
                    //let $hotkey = $(bb['hotkeyPanel']).css('z-index', $(bb['playVideoControlWrap']).css('z-index')-1);

                    //同步显示
                    // let wrap_left = $(bb['dmWrap']).position().left;
                    // let box_left = $(bb['dmBox']).position().left;
                    // $(bb['dmWrap']).css('left', wrap_left + $item_0.width());
                    // $(bb['dmBox']).css('left', box_left - $item_0.width());
                    // $(bb['dmWrap']).css('height', $hotkey.innerHeight());
                    // $(bb['dmWrap']).css('width', $hotkey.innerWidth()-50);
                    // $(bb['dmBox']).css('width', item_2_width);
                    //$(bb['dmWrap']).css('background', 'blue').css('opacity', 0.8);  //test

                    //同步隐藏
                    // waitForTrue(()=> ($(bb['hotkeyPanel']).hasClass('active') === false && $(bb['hotkeyPanel']).css('display') === 'none') || $(bb['dmWrap']).css('display') === 'none', () => {
                    //     //$(bb['hotkeyPanel']).removeClass('active').css('display', 'none');
                    //     $(bb['hotkeyPanelClose']).click();
                    // });

                    let new_left = $item_2.offset().left + $item_2.width();
                    let new_top = $hotkey.offset().top + ($item_2.offset().top + $item_2.height()) - ($hotkey.offset().top + $hotkey.innerHeight());
                    $hotkey.offset({left:new_left, top:new_top});
                    //$hotkey.offset({left:new_left, top:new_top}).find(bb['hotkeyPanelClose']).css('display', 'none');

                    if(set_hotkey_panel_close === false){  //
                        set_hotkey_panel_close = true;
                        $(bb['hotkeyPanelClose']).click(function(){
                            $(bb['hotkeyPanel']).css({left: '50%', top:'50%'});
                        })
                    }
                }else{
                    $(bb['hotkeyPanel']).css({left: '50%', top:'50%'});
                    $(bb['hotkeyPanelClose']).click();
                    // $(bb['dmWrap'])[0].style.cssText = '';
                    // $(bb['dmBox'])[0].style.cssText = '';
                    // $(bb['dmWrap']).css('display', 'block');
                }
            })

/*             //重设置【item_2 - 快捷键说明】
            $item_2.find('#hhh_item_2_hotkey').dblclick(function(){
                let is_active = bb_type.indexOf(BILI_2_X) !== -1 ? $(bb['hotkeyPanel']).hasClass('active') : $(bb['hotkeyPanel']).css('display') !== 'none';
                //2.X和3.X不一样?我来让你一样!
                if(is_active === false){
                    let hotkey_class = bb['hotkeyPanel'].substr(1);
                    $('#hhh_hotkey_panel').clone(true,true).replaceAll($(`.${hotkey_class}:last`)).attr({'id': '', 'class': hotkey_class, 'style': ''});
                    let $hotkey = $(bb['hotkeyPanel']).addClass('active').css('z-index', $(bb['playVideoControlWrap']).css('z-index')-1);

                    //同步显示
                    let wrap_left = $(bb['dmWrap']).position().left;
                    let box_left = $(bb['dmBox']).position().left;
                    $(bb['dmWrap']).css('left', wrap_left + $item_0.width());
                    $(bb['dmBox']).css('left', box_left - $item_0.width());
                    $(bb['dmWrap']).css('height', $hotkey.innerHeight());
                    $(bb['dmWrap']).css('width', $hotkey.innerWidth()-100);
                    $(bb['dmBox']).css('width', item_2_width);
                    //$(bb['dmWrap']).css('background', 'blue').css('opacity', 0.8);  //test


                    //同步隐藏
                    waitForTrue(()=> ($(bb['hotkeyPanel']).hasClass('active') === false && $(bb['hotkeyPanel']).css('display') === 'none') || $(bb['dmWrap']).css('display') === 'none', () => {
                        $(bb['hotkeyPanel']).removeClass('active').css('display', 'none');
                    });

                    let new_left = $item_2.offset().left + $item_2.width();
                    let new_top = $hotkey.offset().top + ($item_2.offset().top + $item_2.height()) - ($hotkey.offset().top + $hotkey.innerHeight());
                    $hotkey.offset({left:new_left, top:new_top}).find(bb['hotkeyPanelClose']).css('display', 'none');
                }else{
                    $(bb['hotkeyPanel']).removeClass('active').css('display', 'none');
                    $(bb['dmWrap'])[0].style.cssText = '';
                    $(bb['dmBox'])[0].style.cssText = '';
                    $(bb['dmWrap']).css('display', 'block');
                }
            }) */

            //set key
            function key_setting(key, status, fn, args){
                if(key === 'volumeControlWhenNonFullScreen'){
                    let pause_status = config.getCheckboxSettingStatus('volumeControlWhenPause');
                    eval(`${fn}(${status}, ${args.screenLeft}, ${args.screenRight}, ${args.delta}, ${pause_status})`);
                } else if(key === 'volumeControlWhenPause'){
                    let non_full_status = config.getCheckboxSettingStatus('volumeControlWhenNonFullScreen');
                    let fn = config.getCheckboxSettingFn('volumeControlWhenNonFullScreen');
                    let args = config.getCheckboxSettingArgs('volumeControlWhenNonFullScreen');
                    eval(`${fn}(${non_full_status}, ${args.screenLeft}, ${args.screenRight}, ${args.delta}, ${status})`);
                } else if(key === 'danmuOpacityControl'){
                    eval(`${fn}(${status}, ${args.delta})`);
                } else if(key === 'hotKeyHint'){
                    is_show_hint = config.getCheckboxSettingStatus(key);
                } else if(!!fn){ // openHotKey | removeVideoTopMask 等
                    eval(`${fn}(${status})`);
                    //Function(`${fn}(${status})`)();
                }
            }

            //重设置【item_2 - 恢复默认设置】
            $item_2.find(bb['dmRightReset']).click(function(){
                for (let [key, { text, status, tips, fn, args }] of Object.entries(config.b_playerCheckbox.options)) {
                    if(get_value(key) === status) continue;

                    $(`#${key}`).find('input').prop('checked', status);
                    set_value(key, status);
                    config.setCheckboxSettingStatus(key, status);

                    key_setting(key, status, fn, args);
                }
            })

            //设置【checkbox】选择
            $item_2.find('#hhh_input_div').click(function(e){
                if(e.target.type === 'checkbox'){
                    let key = bb_type.indexOf(BILI_2_X) !== -1 ? e.target.parentNode.id : e.target.parentNode.parentNode.id;
                    let status = e.target.checked;
                    set_value(key, status);
                    config.setCheckboxSettingStatus(key, status);

                    let fn = config.getCheckboxSettingFn(key);
                    let args = config.getCheckboxSettingArgs(key);

                    key_setting(key, status, fn, args);
                }
            })

            //重设置【item_2 - 恢复默认设置】
            $DSet.on('mouseenter', function(){
                if ($(bb['dmWrap']).css('display') !== 'none') return;
                $item_0.css('height', $item_0[0].hhh_new_height);
                $wrap.css({'height': $item_0.css('height'), 'width': $item_0.css('width')});
                $move.css('transform', 'translateX(0px)');
                $DSet.find('.bui-panel-item-active').removeClass('bui-panel-item-active');
                $item_0.addClass('bui-panel-item-active');
                $(bb['dmWrap'])[0].style.cssText = '';
                $(bb['dmBox'])[0].style.cssText = '';
            })

            //set tips
            waitForTrue(()=> ($tip !== undefined && $(`#${Object.keys(config.sets)[0]}`).length === 1), () => {
                if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"flex"});
                $(bb['dmWrap']).css({"display":"block"});

                for (let [key, { text, status, tips }] of Object.entries(config.sets)) {
                    let $key = $(`#${key}`);
                    $key.width($key.find('label').width());  //调整宽度
                    !!tips && add_tip($tip, $key, {'text':tips, 'millisec':200, 'top':9, 'left':0});
                }

                $(bb['dmWrap']).css({"display":"none"});
                if(bb_type === BILI_3_X) $('.squirtle-controller-wrap').css({"display":"none"});
            })

            //执行所有默认设置
            if(run_default_setting_flag === 'run_default_setting') $item_2.find(bb['dmRightReset']).click();

        }

        //自定义快捷键设置
        //ON - 启用热键,OFF - 关闭热键
        function set_hotkey(open){
            if (open !== ON){
                $(document).off('keyup.hhh_lightoff');
                $(document).off('keydown.hhh_lightoff');
            }else{
                var parent = document;
                var like_shake = false;
                var prev_time = 0;
                is_show_hint = config.getCheckboxSettingStatus('hotKeyHint');

                //up
                $(document).off('keyup.hhh_lightoff');
                $(document).on('keyup.hhh_lightoff',function(e){
                    if(!!e.target.type && e.target.type.toLowerCase().search(/text|textarea/) !== -1) return;
                    if(e.target.className === 'ql-editor') return;
                    if(e.keyCode === 'Y'.charCodeAt() || e.keyCode === 'O'.charCodeAt()) {  //点赞;长按一键三连
                        $(bb['like'])[0].dispatchEvent(new MouseEvent('mouseup'));
                        if(e.keyCode === 'Y'.charCodeAt() && like_shake === false) {
                            let like_text = $(bb['like']).text().match(/.+/)[0];
                            let like_num = like_text.match(/\d+$/)? (+like_text.match(/\d+$/)[0])+1: like_text;
                            if($(bb['likeon']).length === 1) showHint(parent, '#hhh_wordsHint', '取消点赞');
                            else showHint(parent, '#hhh_wordsHint', `点赞成功 ${like_num}`);
                            $(bb['like']).click();
                        }
                        like_shake = false;
                    }
                });

                //down
                $(document).off('keydown.hhh_lightoff');
                $(document).on('keydown.hhh_lightoff',function(e){
                    //log(!!e.target.type === true);
                    //log($(e.target.className));
                    //跳过输入框
                    if(!!e.target.type && e.target.type.toLowerCase().search(/text|textarea/) !== -1) return;
                    if(e.target.className === 'ql-editor') return;

                    //以下使用功能键
                    if(e.shiftKey && (e.keyCode === keycode['left'] || e.keyCode === keycode['right'])) {  //逐帧 shift+ left/right
                        h5Player.pause();
                        for(let move_frames = 1.01; move_frames>0.2;){
                            let move_frames_time = move_frames/fps;
                            h5Player.currentTime = e.keyCode === keycode['left']? +(h5Player.currentTime - move_frames_time).toFixed(3): +(h5Player.currentTime + move_frames_time).toFixed(3);
                            if(prev_time === h5Player.currentTime){  //如果未走帧
                                move_frames /= 2;
                                //log('2.1: '+h5Player.currentTime+' - '+prev_time+' - '+move_frames_time+' - '+move_frames);
                                continue;
                            }
                            else{
                                //log('2.2: '+h5Player.currentTime+' - '+prev_time+' - '+move_frames_time+' - '+move_frames);
                                let total_frame = +(h5Player.duration*fps).toFixed();
                                let current_frame = +(h5Player.currentTime*fps).toFixed();
                                showHint(parent, '#hhh_wordsHint', `${current_frame}/${total_frame}`);
                                prev_time = h5Player.currentTime;
                                break;
                            }
                        }
                        e.stopPropagation();
                    } else if(e.ctrlKey && (e.keyCode === keycode['left'] || e.keyCode === keycode['right'])) {  //+ -30s ctrl+ left/right
                        $(bb['danmakuSwitch']).last().find('input').click().click();
                        h5Player.currentTime = e.keyCode === keycode['left']? h5Player.currentTime - 30: h5Player.currentTime + 30;
                        h5Player.play();
                        dynamicProgress(16, 2);
                    } else if(e.ctrlKey && (e.keyCode === keycode['up'] || e.keyCode === keycode['down'])) {  //ctrl + -播放速度
                        if(config.getCheckboxSettingStatus('keyVideoSpeed') === OFF) return;
                        window.setTimeout((function() {  //长按时保持DOM更新
                            e.keyCode === keycode['up']? video_select_speed(1): video_select_speed(-1);
                        }),10);
                    } else if(e.ctrlKey && e.keyCode === keycode['Enter']) {  //全屏
                        fullscreen();
                    }

                    //以下不使用功能键
                    if(e.ctrlKey || e.altKey || e.shiftKey) return;

                    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站改成点赞了
                        web_fullscreen();
                        e.stopPropagation();
                    } else if(e.keyCode === 'Q'.charCodeAt()) {  //宽屏模式 B站改成投币了
                        is_fullscreen() ? web_fullscreen() : wide_screen();
                        e.stopPropagation();
                    } else if(e.keyCode === 'D'.charCodeAt()) {  //开关弹幕 bilibili增加了关弹幕的快捷键,也是D
                        $(bb['danmakuSwitch']).last().find('input').click();
                        is_show_hint && (is_danmaku_show() === true ? showHint(parent, '#hhh_wordsHint', '开弹幕') : showHint(parent, '#hhh_wordsHint', '关弹幕'));
                        e.stopPropagation();
                    } else if(e.keyCode === 'T'.charCodeAt()) {  //开关顶部弹幕
                        $(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 === 'S'.charCodeAt()) {  //弹幕随屏幕缩放
                        $(bb['settingFs'])[0].checked === false ? showHint(parent, '#hhh_wordsHint', '弹幕随屏幕缩放') : showHint(parent, '#hhh_wordsHint', '弹幕不随屏幕缩放');
                        $(bb['settingFs']).click();
                    } else if(e.keyCode === 'R'.charCodeAt()) {  //开关洗脑循环  B站改成一键三连了
                        $(bb['playSettingRepeatInput'])[0].checked ? showHint(parent, '#hhh_wordsHint', '关洗脑循环') : showHint(parent, '#hhh_wordsHint', '开洗脑循环');
                        $(bb['playSettingRepeatInput']).click();
                        e.stopPropagation();
                    } else if(e.keyCode === 'Z'.charCodeAt() || e.keyCode === 'C'.charCodeAt()) {  //+ -弹幕透明度
                        let inc_percent = e.keyCode === 'Z'.charCodeAt()? -10: 10;
                        window.setTimeout((function() {  //长按时保持DOM更新
                            let opacity = adjust_progress(bb['settingOpacity'], inc_percent, 10, 100);
                            showHint(parent, '#hhh_opacityHint', '透 ' + opacity);
                        }),10);
                    } else if(e.keyCode === 'V'.charCodeAt() || e.keyCode === 'N'.charCodeAt()) {  //+ -弹幕字号
                        let inc_percent = e.keyCode === 'V'.charCodeAt()? -10: 10;
                        window.setTimeout((function() {  //长按时保持DOM更新
                            let opacity = adjust_progress(bb['settingFontsize'], inc_percent, 50, 170);
                            showHint(parent, '#hhh_opacityHint', '字 ' + opacity);
                        }),10);
                    } else if(e.keyCode >= '1'.charCodeAt() && e.keyCode <= '5'.charCodeAt()) {  //弹幕显示区域
                        var area_text = {0:'1/4屏',25:'半屏',50:'3/4屏',75:'不重叠',100:'不限'};
                        var percent = (e.keyCode - '1'.charCodeAt()) * 25;  //((0~4)*25)%
                        set_progress(bb['settingArea'], percent, 0, 100);
                        showHint(parent, '#hhh_wordsHint', area_text[percent]);
                    } else if(e.keyCode === keycode['left'] || e.keyCode === keycode['right']){  //快进时显示醒目进度条 && 段落循环
                        //log( $('#hhh_loop_wrap')[0].hhh_loop_playback_click );
                        if(0&&$('#hhh_loop_wrap')[0].hhh_loop_playback_click === true){
                            //log('快进时显示醒目进度条 && 段落循环');
                            return false;
                        }else{
                            if(config.getCheckboxSettingStatus('reloadDanmuku') === ON) {
                                //恢复重载弹幕效果
                                e.stopPropagation();
                                h5Player.currentTime = e.keyCode === keycode['left']? h5Player.currentTime - 5: h5Player.currentTime + 5;
                                h5Player.play();
                                setTimeout(function(){
                                    $(bb['danmakuSwitch']).last().find('input').click();
                                    $(bb['danmakuSwitch']).last().find('input').click();
                                },0);
                            }
                            dynamicProgress(16, 2);
                        }
                    } else if(e.keyCode === keycode['up'] || e.keyCode === keycode['down']) {  //音量控制,替换系统默认
                        //$(bb['volumeHint']).css({"visibility":"visible"}) //隐藏所有提示,避免提示重叠
                        //$(bb['volumeHint']).css('display', 'none');
                        let diff = e.keyCode === keycode['up']? 0.05: -0.05;
                        window.setTimeout((function() {  //长按时保持DOM更新
                            volume(volume()+diff);
                        }),10);
                        return false;
                    } else if(e.keyCode === keycode['space']) {  //空格键2.X版本不合理,改成和3.X版本一样,3.X版也O了
                        if(!is_fullscreen()){
                            if(is_in_biliplayer === false) e.stopPropagation()
                        }
                    } else if(e.keyCode === keycode['Esc']){  //优先取消右键菜单等
                        if($(bb['hotkeyPanel']).length === 1 && ($(bb['hotkeyPanel']).hasClass('active') === true || $(bb['hotkeyPanel']).css('display') !== 'none')){
                            //$(bb['hotkeyPanel']).removeClass('active').css('display', 'none');
                            $(bb['hotkeyPanel']).find(bb['hotkeyPanelClose']).click();  //慢
                            return false;
                        }
                        if($(bb['playerContextMenu']).hasClass('active') === true || $(bb['playerContextMenu']).hasClass('bpx-player-active') === true ){
                            let evt = new MouseEvent('contextmenu', { clientX:-9999, clientY:-9999 });
                            $(bb['videoWrap'])[0].dispatchEvent(evt);
                            return false;
                        }
                        if($('#hhh_img').length >= 1 && $('#hhh_img').css('display') !== 'none'){
                            $('#hhh_img').css('display', 'none');
                            return false;
                        }

                        //对应 系统快捷键 Q、R、W、E
                    } else if(e.keyCode === 'Y'.charCodeAt() || e.keyCode === 'O'.charCodeAt()) {  //长按一键三连
                        $(bb['like'])[0].dispatchEvent( new MouseEvent('mousedown') );
                        if(like_shake === false) like_shake = !!$('.van-icon-videodetails_like.shake').length;
                    } else if(e.keyCode === 'U'.charCodeAt()) {  //投币
                        $(bb['coin']).click();
                    } else if(e.keyCode === 'I'.charCodeAt()) {  //收藏
                        $(bb['collect']).click();

                        //TEST
                    } else if(e.keyCode === 'X'.charCodeAt() || e.keyCode === keycode['/']) {  //TEST 显示、隐藏video-control
                        if($(bb['playArea']).hasClass('video-control-show') === true) $(bb['playVideoControlWrap']).mouseout();
                        else $(bb['playVideoControlWrap']).mousemove();
                    } else if(e.keyCode === 'V'.charCodeAt()) {  //TEST
                        //if(bb_type===BILI_3_X) $('.bpx-player-dm-setting-wrap').css('display','block');
                        $('.bilibili-player-video-danmaku-setting-wrap').mouseover();
                        //$('.bilibili-player-area.video-state-blackside').attr('class', 'bilibili-player-area video-state-blackside video-state-pause video-control-show');
                    }else{
                        //console.dir(e.keyCode);
                    }
                });
            }
        }

        //因为遮挡弹幕,去掉全屏时鼠标悬停时产生的顶端mask
        function removeVideoTopMask(is_remove){
            let top_mask_class = bb['videoTopMask'].substr(1);
            if(is_remove === ON) $(bb['videoTopMask']).attr('id', top_mask_class).removeClass();
            else $(`#${top_mask_class}`).addClass(top_mask_class);
        }

        //播放关灯,暂停开灯,跳过充电
        function lightOffWhenPlaying(status){
            $(h5Player).off('play.hhh'); if(status === OFF) return;
            $(h5Player).on('play.hhh', ()=> !is_lightoff() && lightoff_btn());
        }
        function lightOnWhenPause(status){
            $(h5Player).off('pause.hhh'); if(status === OFF) return;
            $(h5Player).on('pause.hhh', ()=> is_lightoff() && lightoff_btn());
        }
        function jumpElectric(status){
            $(h5Player).off('ended.hhh'); if(status === OFF) return;
            $(h5Player).on('ended.hhh', ()=> $(bb['playJumpElectric']).click());
        }

        //双击或中键全屏
        function dblclickFullScreen(status){
            $(bb['videoWrap']).off('mousedown.hhh'); if(status === OFF) return;
            $(bb['videoWrap']).on('mousedown.hhh', function(e){
                if(e.button === 1 || e.button === 4 || e.button === 3) {  // 1中键
                    if(e.button === 1) web_fullscreen();
                    else fullscreen();
                    e.preventDefault(); e.stopPropagation();
                }
            });
            //$(bb['playTipWrap']).dblclick(function(){ fullscreen() });  //2.66自带双击全屏
        }

        //调节视频倍速
        function video_select_speed(level) {
            let data_x = ['0.5x', '0.75x', '1.0x', '1.25x', '1.5x', '2.0x'];
            let curr_x = $(bb['videoSpeedActive']).text();
            let x = data_x[data_x.indexOf(curr_x) + level];
            log(curr_x+' - '+x+' - '+data_x.indexOf(curr_x));
            if(x !== undefined) $(`${bb["videoSpeed"]}:contains("${x}")`).click();
            showHint(parent, '#hhh_wordsHint', x);
        }

        //扩展播放倍速范围
        function extend_video_speed(){
            let $speedul = $(bb['videoSpeedActive']).parent();
            let $li_0_1x = $speedul.find('li:first').clone(true, true).text('0.1x');
            $speedul.append($li_0_1x);
            let $li_1_7_5x = $speedul.find('li:first').clone(true, true).text('1.75x');
            $speedul.find('li:contains(2.0x)').after($li_1_7_5x);
            let $li_3x   = $speedul.find('li:first').clone(true, true).text('3.0x');
            let $li_3_5x = $speedul.find('li:first').clone(true, true).text('3.5x');
            let $li_4x   = $speedul.find('li:first').clone(true, true).text('4.0x');
            let $li_4_5x = $speedul.find('li:first').clone(true, true).text('4.5x');
            let $li_5x   = $speedul.find('li:first').clone(true, true).text('5.0x');
            $speedul.prepend($li_3x); $speedul.prepend($li_3_5x); $speedul.prepend($li_4x); $speedul.prepend($li_4_5x); $speedul.prepend($li_5x);

            $speedul.find('li').each(function(e){
                let $this = $(this);
                $this.attr('data-value', `${$this.text().split('x')[0]}`);
            })

            $speedul.on('click', function(e){
                let $li = $(e.target);
                let speed = $li.attr('data-value');
                if(speed !== undefined){
                    h5Player.playbackRate = speed;
                    setTimeout(function(){
                        let speed_active = bb_type === BILI_3_X? 'active': 'bilibili-player-active';
                        $(bb['videoSpeedActive']).removeClass(speed_active);
                        $li.addClass(speed_active);
                        $(bb['videoSpeedName']).text($li.text());
                    },0)
                }
            })
        }

        //主程序
        function run(){

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

            //bpx test
            function bpx_test(){
                log('-------------------');
                log('ver: '+ver);
                log('fps: '+fps);
                log('------h5Player-----');
                dir(h5Player);
                log('currentTime  : '+h5Player.currentTime);
                log('duration     : '+h5Player.duration);
                log('playbackRate : '+h5Player.playbackRate);
                log('volume       : '+h5Player.volume);
                log('paused       : '+h5Player.paused);
                log('pause()      : '+'h5Player.pause()');
                log('videoHeight  : '+h5Player.videoHeight);
                log('videoWidth   : '+h5Player.videoWidth);
                log('-------------------');
            }

            /*-----------------------------------
             *初始化等
             *----------------------------------*/
            //保存设置信息 && 快捷键信息
            config.saveCheckboxSetting();

            for (let [key, { text, status }] of Object.entries(config.sets)) {
                if(get_value(key) === undefined) set_value(key, status);
                else config.sets[key]['status'] = JSON.parse(get_value(key));
            }

            //取得h5 video & window.player
            h5Player = ($(`${bb['video']} video`)[0] || $(`${bb['video']} bwp-video`)[0]);
            //bili_player = window.player;

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

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

            //保存tip
            $('.bilibili-player-video-danmaku-setting-left-ps').mouseover();
            waitForTrue(()=> $('.player-tooltips.tip.top-center.animation').length === 1, () => {
                $tip = $('.player-tooltips.tip.top-center.animation').clone().removeClass('active');
                $tip.find('.tooltip').css('background-color', 'rgba(0,0,0,0.9)');
                $('.bilibili-player-video-danmaku-setting-left-ps').mouseout();
            });

            //激活系统播放设置,以此调用系统关灯等
            //去掉mouseleave(),否则如果太快执行mouseleave()无法激活关灯class,应该是mouseenter()未执行完就被mouseleave打断了
            $(`${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');
            });

            //取得视频fps
            get_video_fps_ver();

            //取得版本号
            //get_ver();

            //激活系统提示添加音量等自定义提示DOM
            pick_volume_hint();

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

            //初始化自定义设置
            init_setting();

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

            //判断当前鼠标点击焦点
            $(document).mouseup(function(e){
                if(e.originalEvent === undefined) return;
                let path = e.originalEvent.path;
                curr_focus = path[0];
                is_in_biliplayer = false;
                $(path).each(function(){
                    if(this.id === 'bilibili-player') { is_in_biliplayer = true; return; }
                })
                //隐藏封面 2.x && 3.x
                if(is_in_biliplayer == false || e.target.className === 'bilibili-player-dm-tip-wrap' || e.target.tagName.toLowerCase() === 'video'){
                    $('#hhh_img').css('display', 'none');
                }
            })

            //扩展播放倍速范围
            extend_video_speed();

            //修复选择历史弹幕时弹幕填装信息丢失问题
            fix_danmaku_info();

            //自动运行
            if(config.getCheckboxSettingStatus('autoPlay') === ON && $(bb['playSettingAutoplay'])[0].checked === false) $(bb['playSettingAutoplay']).click();//开启自动播放
            if(config.getCheckboxSettingStatus('lightOff') === ON) lightoff_btn();  //自动关灯
            if(config.getCheckboxSettingStatus('autoFullScreen') === ON) fullscreen();  //自动全屏
            if(config.getCheckboxSettingStatus('autoWebFullScreen') === ON) web_fullscreen();  //自动网页全屏
            if(config.getCheckboxSettingStatus('videoRepeat') === ON) $(bb['playSettingRepeatInput']).click();  //开启洗脑循环

            //双击或中键全屏
            dblclickFullScreen(config.getCheckboxSettingStatus('dblclickFullScreen'));

            //非全屏滚轮音量调节
            //两个参数指定屏幕范围(按百分比),第三个参数表示滚动一下增加的音量百分比,参数四表示暂停时是否调节
            let args = config.getCheckboxSettingArgs('volumeControlWhenNonFullScreen');
            wheel_volumeHint(config.getCheckboxSettingStatus('volumeControlWhenNonFullScreen'), args.screenLeft,args.screenRight,args.delta, config.getCheckboxSettingStatus('volumeControlWhenPause'));

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

            //因为遮挡弹幕,去掉全屏时鼠标悬停时产生的顶端mask
            removeVideoTopMask(config.getCheckboxSettingStatus('removeVideoTopMask'));

            //播放关灯,暂停开灯,跳过充电鸣谢
            lightOffWhenPlaying(config.getCheckboxSettingStatus('lightOffWhenPlaying'));
            lightOnWhenPause(config.getCheckboxSettingStatus('lightOnWhenPause'));
            jumpElectric(config.getCheckboxSettingStatus('jumpElectric'));

            //记忆洗脑循环
            if(config.getCheckboxSettingStatus('rememberVideoRepeat') === ON && config.getCheckboxSettingStatus('videoRepeat') !== ON) {
                if(JSON.parse(get_value('hhh-rememberVideoRepeat', $(bb['playSettingRepeatInput'])[0].checked)) === true) $(bb['playSettingRepeatInput']).click();  //localStorage只能保存字符串
                $(bb['playSettingRepeatInput']).click(function() {
                    set_value('hhh-rememberVideoRepeat', $(bb['playSettingRepeatInput'])[0].checked);
                });
            };

            /*-----------------------------------
             *键盘控制
             *----------------------------------*/
            set_hotkey(config.getCheckboxSettingStatus('openHotKey'));

            /*设置界面
            //viewBox="10 8.5 10 12"
            $('.bilibili-player-video-danmaku-setting').clone(false,false).insertBefore($('#hhh_lightoff')).attr('id', 'hhh_setting')
            $('#hhh_setting>span>svg')[0].attributes[1].value = '10 8.5 10 12'
            $('#hhh_setting>span>svg>path:first').remove()
            */

            //段落循环
            //loop_playback();

            //TEST
            bpx_test();

            log(bb)

            // log($('.bilibili-player-video-danmaku-switch .bui-switch-input').length);
            // log($('.bilibili-player-video-danmaku-switch .bui-switch-input')[0].checked);
            // log($('.bilibili-player-video-danmaku-switch .bui-switch-input')[1].checked);
            // setTimeout(function(){log($('.bilibili-player-video-danmaku-switch .bui-switch-input')[0].checked);
            //                       log($('.bilibili-player-video-danmaku-switch .bui-switch-input')[1].checked);},1000)
        }

        //段落循环
        function loop_playback(){
            if(bb_type.indexOf(BILI_2_X) === -1) return false;

            var is_begin = true,
                first = true;

            function show_loop_time(sign_show){
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-cut-img').hide();
                if(sign_show !== 'sign_show') $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-sign').hide();
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail').show();
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail').css('opacity',1);
            }
            function hide_loop_time(){
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail').css({display:''});
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-cut-img').show();
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-sign').show();
            }
            //loop显示状态切换
            function loop_state_switch(state){
                $('#hhh_loop_wrap')[0].hhh_loop_state_switch = state;
                let $p1 = $('#hhh_loop_1'), $p2 = $('#hhh_loop_2'), $bar = $('#hhh_loop_bar');
                if(state === 0){  //no loop
                    $p1.hide(), $p2.hide(), $bar.hide();
                }else if(state === 1){  //loop 1
                    if($p1[0].hhh_seconds) $p1.show();
                    if($p2[0].hhh_seconds) $p2.show();
                    if($p1[0].hhh_seconds && $p2[0].hhh_seconds) $bar.show();
                }else{  //loop 2
                    $p1.hide(), $p2.hide();
                    if($p1[0].hhh_seconds && $p2[0].hhh_seconds) $bar.show();
                }
            }
            //更新
            function loop_update($hhh_loop, o){
                //function PrefixZero(num, n) { return (Array(n).join(0) + num).slice(-n) }
                //time = PrefixZero(Math.floor(time/60),2) + ':' + PrefixZero(time%60,2);
                var left = 0,
                    seconds = 0,
                    rect = $('.bilibili-player-video-progress')[0].getBoundingClientRect();

                if(o.left !== undefined){
                    left = o.left - rect.x;
                    if(left < 0 || left > rect.width) return;
                    //Position To Time
                    seconds = Math.round(left/$('.bilibili-player-video-progress').width()*h5Player.duration);
                }else if(o.seconds !== undefined){
                    //Time To Position
                    left = o.seconds/h5Player.duration*$('.bilibili-player-video-progress').width();
                    if(left < 0 || left > rect.width) return;
                    seconds = o.seconds;
                }else{ log('参数错误',o); return;}

                //updata x
                $hhh_loop.css({left:left});
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail').css({left:left});

                //updata time
                $hhh_loop[0].hhh_seconds = seconds;
                function sec2str(t){
                    var d = Math.floor(t/86400),
                        h = (''+Math.floor(t/3600) % 24).slice(-2),
                        m = ('0'+Math.floor(t/60)%60).slice(-2),
                        s = ('0' + t % 60).slice(-2);
                    return (d>0?d+'d ':'')+(h5Player.duration>=3600?h+':':'')+m+':'+s;
                }
                let time = sec2str(seconds);
                $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text(time);

                //updata bar
                let t1 = $('#hhh_loop_1')[0].hhh_seconds;
                let t2 = $('#hhh_loop_2')[0].hhh_seconds;
                if(t1 && t2){
                    t1 = $('#hhh_loop_1').css('left').slice(0,-2);
                    t2 = $('#hhh_loop_2').css('left').slice(0,-2);
                    let begin = Math.min(t1,t2);
                    let end = Math.max(t1,t2);
                    $('#hhh_loop_bar').css({display:'block',width:`${end-begin}px`,left:`${begin}px`});
                }
            }
            //更新位置
            function resize_updata(){
                let $p1 = $('#hhh_loop_1');
                let $p2 = $('#hhh_loop_2');
                let $bar = $('#hhh_loop_bar');
                if($p1.length !== 1 || $p2.length !== 1 && $bar.length !== 1) return;

                let t1 = $p1[0].hhh_seconds;
                let t2 = $p2[0].hhh_seconds;
                let rect = $('.bilibili-player-video-progress')[0].getBoundingClientRect();
                let newleft = t1/h5Player.duration*rect.width;
                $p1.css('left', newleft);
                newleft = t2/h5Player.duration*rect.width;
                $p2.css('left', newleft);

                //log($p1.css('left'),$p2.css('left'));
                //log('------'+newleft);

                t1 = $p1.css('left').slice(0,-2);
                t2 = $p2.css('left').slice(0,-2);
                let begin = Math.min(t1,t2);
                let end = Math.max(t1,t2);
                $bar.css({left:begin, width:end-begin});
            }

            //css
            $('#hhh_head_style').remove();  //test
            if($('#hhh_head_style').length<1){
                $('head:first').append(`<style id="hhh_head_style" type="text/css">
                .hhh-bilibili-player-video-progress-detail {
                    position: absolute;
                    bottom: 7px;
                    left: 100px;
                    overflow: visible;
                    width: 20px;
                    height: 36px;
                    margin-left: -10px;
                    text-align: center;
                    z-index: 1;
                    pointer-events: none;
                    display: none;
                }
                .hhh-bilibili-player-video-progress-detail-sign {
                    cursor: pointer;
                    width: 8px;
                    height: 16px;
                    margin: 0 auto;
                    position: absolute;
                    overflow: hidden;
                    top: 27px;
                    left: 6px;
                }
                .hhh-bilibili-player-video-progress-detail-sign-down {
                    width: 0;
                    height: 0;
                    border-color: #FFA500 transparent transparent;
                    border-style: solid;
                    border-width: 4px;
                    position: relative;
                }
                .hhh-bilibili-player-video-progress-detail-sign-up {
                    margin-top: 8px;
                    width: 0;
                    height: 0;
                    border-color: transparent transparent #FFA500;
                    border-style: solid;
                    border-width: 4px;
                    position: relative;
                }
                </style>`);
            }

            //loop wrap
            let progheight = $('.bilibili-player-video-progress .bui-track').parent().css('height');
            //let progalignitem = $('.bilibili-player-video-progress .bui-track').parent().css('align-items');
            let progclass = $('.bilibili-player-video-progress .bui-track').parent().attr('class');
            $('.bilibili-player-video-progress .bui-track').wrap(`<div id="hhh_loop_wrap" class="${progclass}" style="width:100%; padding:0px"></div>`);
            $('#hhh_loop_wrap')[0].hhh_loop_state_switch = 1;
            //$('.bilibili-player-video-progress .bui-track').wrap(`<div id="hhh_loop_wrap" style="width:100%; height:${progheight}; display:flex; align-items:${progalignitem}"></div>`);

            let $bar = $('#hhh_loop_wrap').find('.bui-bar-wrap');
            let $schedule = $('#hhh_loop_wrap').find('.bui-schedule-wrap');
            $bar = $bar.length === 1? $bar: $schedule.length === 1? $schedule: log('not bui-bar-wrap  bui-schedule-wrap');
            $bar.children('div:first').clone(true,true).appendTo($bar)
                                      .css({transform:'scaleX(0.999999)'})  //配合其他transform,否则height不同,scaleX会改变height,bug?
                                      .css({background:'rgba(255,165,0,0.5)',display:'none'})
                                      .attr('id','hhh_loop_bar');

            //前后箭头node
            let detail = `<div id="hhh_id" class="hhh-bilibili-player-video-progress-detail" style="left:78.0475px;pointer-events:auto;z-index:-1">
                            <div class="bilibili-player-video-progress-detail-container" style="margin-left: -22px; width: 60px;">
                                <div class="bilibili-player-video-progress-detail-img" style="width: 60px; height: 18px;">
                                   <div class="bilibili-player-video-progress-detail-time" style="left:0px">00:01</div>
                                </div>
                            </div>
                            <div class="hhh-bilibili-player-video-progress-detail-sign">
                                <div class="hhh-bilibili-player-video-progress-detail-sign-down"></div>
                            </div>
                        </div>`;
            $('.bilibili-player-video-control-top').append(detail.replace(/hhh_id/, 'hhh_loop_1'));
            $('.bilibili-player-video-control-top').append(detail.replace(/hhh_id/, 'hhh_loop_2'));

            //设置起点和终点
            $('#hhh_loop_wrap')[0].hhh_loop_playback_click = false;
            $('#hhh_loop_wrap').mousedown(function(e){
                if(e.ctrlKey === true){
                    return false
                }
            }).mouseup(function(e){
                if(e.ctrlKey === true){
                    $('.bilibili-player-video-toast-wrp').css('z-index', 0);
                    loop_state_switch(1);
                    var begin_left = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail').css('left');
                    let $hhh_loop = is_begin? $('#hhh_loop_1'): $('#hhh_loop_2');
                    is_begin = !is_begin;
                    loop_update($hhh_loop, {left:e.pageX});
                    $hhh_loop.css({left:`${begin_left}`}).css('display', 'block');
                    let time = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text();
                    $hhh_loop.find('.bilibili-player-video-progress-detail-time').text(time);

                    this.hhh_loop_playback_click = $hhh_loop[0].id;

                    if(first === true){
                        first = false;

                        //判断当前鼠标点击焦点
                        $(document).mouseup(function(e){
                            if(!e.ctrlKey && $('#hhh_loop_wrap')[0].hhh_loop_playback_click) $('#hhh_loop_wrap')[0].hhh_loop_playback_click = false;
                        });

                        //time now
                        $('.bilibili-player-video-time-now')[0].addEventListener('DOMNodeInserted', function(e) {
                            if($('#hhh_loop_wrap')[0].hhh_loop_state_switch && $('#hhh_loop_wrap')[0].hhh_loop_state_switch !== 0){
                                let t1 = $('#hhh_loop_1')[0].hhh_seconds;
                                let t2 = $('#hhh_loop_2')[0].hhh_seconds;
                                let begin = Math.min(t1,t2);
                                let end = Math.max(t1,t2);
                                    //log(t1+' - '+t2);
                                if(h5Player.currentTime > end){
                                    //log(t1+' - '+t2);
                                    h5Player.currentTime = begin;
                                }
                            }
                        });

                        //拖动确定范围
                        $('#hhh_loop_1, #hhh_loop_2').mouseenter(function(e){
                            $(this).css({'cursor': 'w-resize'});
                        }).mousedown(function(e){
                            var $this = $(this);
                            var doc = document;

                            if(e.ctrlKey){
                                loop_state_switch(0);
                            }else{
                                loop_update($this, {left:e.pageX});

                                doc.onmousemove = function(e){
                                    loop_update($this, {left:e.pageX});
                                    let time = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text();
                                    $this.find('.bilibili-player-video-progress-detail-time').text(time);
                                };

                                doc.onmouseup = function(e){
                                    //清除事件
                                    doc.onmousemove=null;
                                    doc.onmouseup=null;
                                    //hide_loop_time();

                                    let time = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text();
                                    $this.find('.bilibili-player-video-progress-detail-time').text(time);

                                    //$this.find('.bilibili-player-video-progress-detail-container').show();

                                    $('#hhh_loop_wrap')[0].hhh_loop_playback_click = $this[0].id;
                                    return false;
                                }
                            }
                        });

                        //监听视频窗口大小变化
                        var ro = new ResizeObserver( entries => {
                            for (let entry of entries) {
                                //更新loop位置
                                resize_updata();
                            }
                        });

                        // Observe one or multiple elements
                        //squirtle-video-time-now 2.X   bilibili-player-video-time-now 3.X
                        ro.observe($('.bilibili-player-video-wrap')[0]);
                    }

                    return false;
                }else{
                    this.hhh_loop_playback_click = false;
                }
            });

            //保存sign原color
            $('.bilibili-player-video-progress-slider')[0].hhh_sign_color = $('.bilibili-player-video-progress-detail-sign-down').css('border-top-color');

            //键盘 down
            $(document).off('keydown.hhh_progress');
            $(document).on('keydown.hhh_progress',function(e){
                if(e.keyCode === keycode['Ctrl']) {
                    if($('.bilibili-player-video-progress').hasClass('bilibili-player-show') === true){
                        $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-sign-down').css('border-top-color', '#FFA500');
                        $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-sign-up').css('border-bottom-color', '#FFA500');
                        show_loop_time('sign_show');
                    }
                } else if(e.keyCode === keycode['left'] || e.keyCode === keycode['right']){  //段落循环
                    if($('#hhh_loop_wrap')[0].hhh_loop_playback_click !== false && $('#hhh_loop_1').css('display') !== 'none'){
                        $('.bilibili-player-area').addClass('video-control-show');
                        let $hhh_loop = $('#'+$('#hhh_loop_wrap')[0].hhh_loop_playback_click);
                        let old_seconds = $hhh_loop[0].hhh_seconds;
                        let time1 = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text();
                        let seconds = e.keyCode === keycode['right']? ++$hhh_loop[0].hhh_seconds: --$hhh_loop[0].hhh_seconds;
                        loop_update($hhh_loop, {seconds:seconds});
                        let time2 = $('.bilibili-player-video-progress .bilibili-player-video-progress-detail-time').text();
                        if(time1 !== time2) {
                            $hhh_loop.find('.bilibili-player-video-progress-detail-time').text(time2)
                        }else{
                            $hhh_loop[0].hhh_seconds = old_seconds;
                        }
                        return false;
                    }
                }else if(e.keyCode === 'L'.charCodeAt()){
                    if($('#hhh_loop_1')[0].hhh_seconds !== undefined){
                        $('.bilibili-player-area').addClass('video-control-show');
                        $('#hhh_loop_wrap')[0].hhh_loop_state_switch = ++$('#hhh_loop_wrap')[0].hhh_loop_state_switch % 3;
                        loop_state_switch($('#hhh_loop_wrap')[0].hhh_loop_state_switch);
                    }
                }
            });

            //键盘 up
            $(document).off('keyup.hhh_progress');
            $(document).on('keyup.hhh_progress',function(e){
                if(e.keyCode === keycode['Ctrl']) {
                    //if($('.bilibili-player-video-progress').hasClass('bilibili-player-show') === true){
                        $('.bilibili-player-video-progress-detail-sign-down').css('border-top-color', $('.bilibili-player-video-progress-slider')[0].hhh_sign_color);
                        $('.bilibili-player-video-progress-detail-sign-up').css('border-bottom-color', $('.bilibili-player-video-progress-slider')[0].hhh_sign_color);
                        hide_loop_time();
                    //}
                } else if(e.keyCode === keycode['left'] || e.keyCode === keycode['right']){  //段落循环
                    if($('#hhh_loop_wrap')[0].hhh_loop_playback_click !== false){
                        //hide_loop_time();
                        return false;
                    }
                }
            });
        }

        //增加当前在线视频预览
        function run_preview(){
            if($('#hhh_online_list_style').length === 1) return;

            function hide(parent, selector, show_or_hide){
                var o = $();
                if($.isArray(selector) === true){
                    $.each(selector, function(i,v){
                        o = o.add(v);
                    })
                }else{
                    o = $(selector);
                }
                //显示及渐隐效果(抄bilibili^^)
                clearTimeout(parent.showHintTimer),
                    o.stop().show(),
                    parent.showHintTimer = window.setTimeout((function() {
                        o.animate({
                            opacity: 0
                        }, 600, (function() {
                            $(this).hide()
                        }))
                    }
                ), 0)
            }
            function show(parent, selector, show_or_hide){
                var o = $();
                if($.isArray(selector) === true){
                    $.each(selector, function(i,v){
                        o = o.add(v);
                    })
                }else{
                    o = $(selector);
                }
                //显示及渐隐效果(抄bilibili^^)
                clearTimeout(parent.showHintTimer),
                    parent.showHintTimer = window.setTimeout((function() {
                        o.stop().show(),
                        o.animate({
                            opacity: 1
                        }, 600, (function() {
                            $(this).show()
                        }))
                    }
                ), 300)
            }
            if($('#hhh_online_list_style').length<1){
                $('.online-list').append(`<style id="hhh_online_list_style" type="text/css">
                    .hhh-preview-bg {
                        top: 13px;  //硬编码
                        z-index: 2;
                        height: 100%;
                    }
                    .hhh-preview-wrapper {
                        top: 0;
                        z-index: 4;
                        padding: 0 5px 5px;
                        box-sizing: border-box;
                        background-color: #000;
                    }
                    .hhh-preview-bg, .hhh-preview-wrapper {
                        position: absolute;
                        display: none;
                        left: 0;
                        width: 100%;
                    }
                    .hhh-preview-progress {
                        width: 100%;
                        height: 2px;
                        margin-top: 5px;
                        background-color: hsla(0,0%,100%,.4);
                        border-radius: 1px;
                    }
                    .hhh-preview-progress-bar {
                        width: 0;
                        height: 2px;
                        border-radius: 1px;
                        background-color: #fff;
                    }
                    </style>`);
            }
            var bvs = {},
                box_width = 0,
                bg_img_row = 0,
                bg_y_block_len = 0,
                bg_img_totle = 0;
            $('.online-list>.ebox>a>div').mouseenter(function(e){
                this.state = 'enter';
                let $lazy_img = $(this);
                let bvid = $lazy_img.parent().attr('href').match(/BV\w+$/);
                bvid = bvid && bvid[0];
                this.bvid = bvid;
                if(bvs[bvid] === undefined){
                    bvs[bvid] = $lazy_img.parent().attr('title');
                    $.getJSON("https://api.bilibili.com/x/player/videoshot", { bvid: bvid, index: "1" },
                        function(json){
                            let bg_img = json.data.image[0];
                            box_width = $lazy_img.width();
                            bg_img_totle = json.data.index.length > (json.data.img_x_len*json.data.img_x_len)? (json.data.img_x_len*json.data.img_x_len): json.data.index.length;
                            bg_img_row = bg_img_totle < json.data.img_x_len? bg_img_totle: json.data.img_x_len;
                            bg_y_block_len = json.data.img_y_size/json.data.img_x_size*box_width;
                            bvs[bvid] = {box_width:box_width, bg_img_totle:bg_img_totle, bg_img_row:bg_img_row, bg_y_block_len:bg_y_block_len};

                            //log(bg_img_row+' - '+bg_img_totle+' - '+bg_y_block_len);
                            //log(bvs[bvid]);
                            $lazy_img.css({'overflow':'hidden', 'position':'relative'});
                            $lazy_img.append(`<div class="hhh-preview-bg" style="background-position: 0px 0px; background-size: ${box_width*bg_img_row}px; background-image: url('${bg_img}');"></div>
                                              <div class="hhh-preview-wrapper" style="display: none; opacity: 1;"><div class="hhh-preview-progress"><div class="hhh-preview-progress-bar" style="width: 50%;"></div></div></div>`);
                            if($lazy_img[0].state === 'enter') show($lazy_img[0], [$lazy_img.find('.hhh-preview-bg'), $lazy_img.find('.hhh-preview-wrapper')], 'show');
                    });
                }else{
                    show($lazy_img[0], [$lazy_img.find('.hhh-preview-bg'), $lazy_img.find('.hhh-preview-wrapper')], 'show');
                }
            }).mouseleave(function(){
                this.state = 'leave';
                hide(this, [$(this).find('.hhh-preview-bg'), $(this).find('.hhh-preview-wrapper')], 'hide');
            }).mousemove(function(e){
                //log(this.bvid);
                let obv = bvs[this.bvid];
                let amounts = Math.floor(e.offsetX/(obv.box_width/obv.bg_img_totle));
                let x =  Math.floor(amounts % obv.bg_img_row) * -obv.box_width;
                x = Math.min(Math.max(x,-obv.box_width*(obv.bg_img_totle-1)),0);
                let y =  Math.floor(amounts/obv.bg_img_row) * -obv.bg_y_block_len;
                //log('---'+box_width+' - '+bg_img_totle);
                //log(e.offsetX+' - '+amounts+' - '+x+' - '+y+' - '+bg_y_block_len+' - '+Math.floor(amounts/bg_img_row));
                $(this).find('.hhh-preview-bg').css({'background-position':`${x}px ${y}px`});

                let w = Math.round(e.offsetX/obv.box_width*100);
                $(this).find('.hhh-preview-progress-bar').css({'width':`${w}%`});
            })
        }

        //动态首页直接显示隐藏content
        function run_content(){
            if($('[hhh_has_content]').length < $('.bili-dyn-content__orig__major').length){
                $('.bili-dyn-content__orig__major').each(function(){
                    let $major = $(this);
                    let $hhh_has_content = $major.find('[hhh_has_content]');
                    if($hhh_has_content.length >= 1) return true;
                    //$major.attr('hhh_has_content', true);

                    //显示隐藏标题
                    let $title = $major.find('.bili-dyn-card-video__title');
                    if($title.length >= 1){
                        let font_size = $title.css('font-size');
                        let line_height = +font_size.match(/\d+/)[0] + 5;  //估算
                        let h = $title.removeClass('bili-dyn-card-video__title').css({'font-size':font_size}).height();
                        //log(line_height+' - '+h)
                        $title.addClass('bili-dyn-card-video__title');
                        if(h > line_height*2){
                            $title.attr('title', $title.text())
                        }
                    }

                    //显示隐藏content
                    let $content = $major.find('.bili-dyn-card-video__desc');
                    if($content.length >= 1){
                        //console.log($content.text().slice(0,10)+ ' : ' +$content.height());
                        let line_height = $content.css('line-height');
                        //log($content.height());
                        let font_size = $content.css('font-size');
                        let h = $content.removeClass('bili-dyn-card-video__desc').css({'line-height':line_height, 'font-size':font_size}).height();
                        line_height = line_height.match(/\d+/)[0];
                        //console.log('---line_h:'+line_height+'  h: '+h+'  title: '+$major.find('.title').text());
                        $content.addClass('bili-dyn-card-video__desc');
                        $content.attr('hhh_has_content', true);

                        if(h > line_height*2){
                            $major.find('.bili-dyn-card-video').height('auto');
                            $major.find('.bili-dyn-card-video__body').css('display', 'block');
                            $major.find('.bili-dyn-card-video__header').height(127);

                            //console.log(line_height*2);
                            $content.css({'padding-top':'8px'});
                            $content.height(line_height);
                            let $expand = $(`<div style="color:#178bcf; font-size:12px; line-height:22px; display:block" onMouseOver="this.style.color='#00b5e5'" onMouseOut="this.style.color='#178bcf'">展开</div>`).insertAfter($content);
                            //let $expand = $(`<div class="expand-btn" data-v-98357e68 style="font-size:12px; line-height:22px; display:block" onMouseOver="this.style.color='#00b5e5'" onMouseOut="this.style.color='#178bcf'">展开</div>`).insertAfter($content);
                            $expand.add($content).click(function(){
                                if($expand.text() === '展开'){
                                    //console.log('=='+$content.height()+'==='+$content.css('line-height').match(/\d+/)[0]);
                                    $content.css({height:'auto', '-webkit-box-orient':'inline-axis'});
                                    $expand.text('收起');
                                }else{
                                    $content.height(line_height);
                                    $content.css({'-webkit-box-orient':'vertical'});
                                    $expand.text('展开');
                                }
                                return false
                            });
                        }
                    }
                })
            }
        }

        function run_history(){
            $.get("https://api.bilibili.com/x/web-goblin/history/search", { pn:"1", keyword: "12", business: "all" },
                function(json){
                    console.log(json)
            });
        }

        function run_rcmd_box(){
            var rcmd_box_data = [$('.rcmd-box').clone(false,false)];
            let $cbtn = $('.change-btn');
            let h = $cbtn.outerHeight();
            let w = $cbtn.outerWidth();
            let is_change_break = null;
            let curr_rcmd_box_num = 0;

            //list-box left
            $('#elevator').css({left:`calc(50% + ${w+3+20}px)`});  //calc(50% + 3px);

            //refresh
            $cbtn.click(()=>{
                $('.rcmd-box-wrap')[0].addEventListener('DOMSubtreeModified', function(e) {
                    let eve_this = this;
                    if(typeof e.target.className === 'string' && e.target.className === 'rcmd-box'){
                        clearTimeout(is_change_break);
                        is_change_break = setTimeout(function() {
                            //log("推荐页面刷新完毕");
                            eve_this.removeEventListener('DOMSubtreeModified', arguments.callee);
                            rcmd_box_data.push($('.rcmd-box').clone(false,false));
                            curr_rcmd_box_num = rcmd_box_data.length - 1;
                            $('#hhh_cbtn_num').text(`${rcmd_box_data.length}/${rcmd_box_data.length}`);
                            if(rcmd_box_data.length >= 10){ $('#hhh_cbtn_num').css({width:'37px', right:'-41px'}) }
                            //log(rcmd_box_data.length)
                        }, 50);
                    }
                })
            });

            let $new_cbtn = $cbtn.clone(false, false).empty();

            //num
            $('.rcmd-box-wrap').append($new_cbtn.clone().attr('id','hhh_cbtn_num')
                                                        .css({height:'21px', 'line-height':'21px', top:`${h+2}px`})
                                                        .css({cursor:'default'})
                                                        .css({padding:'0px', background:'#e2e2e2'}).append('1/1'));
            let $cbtn_num = $('#hhh_cbtn_num');
            let cbtn_h = $cbtn_num.outerHeight() + 3;

            //left
            $('.rcmd-box-wrap').append($new_cbtn.clone().attr('id','hhh_cbtn_zuo').css({height:'auto', top:`${h+1+cbtn_h}px`})
                                                                                  .css({'border-bottom':'0px', 'border-bottom-left-radius':'0px', 'border-bottom-right-radius':'0px'})
                                                                                  .append('<i class="bilifont bili-icon_caozuo_xiangzuo"></i>'));
            let $cbtn_zuo = $('#hhh_cbtn_zuo');
            $cbtn_zuo.click(function(){
                //激活动画
                let $i = $(this).find('i');
                $i.addClass('active');
                setTimeout(function(){ $i.removeClass('active') },500);
                //恢复前一个list
                curr_rcmd_box_num = Math.max(curr_rcmd_box_num-1, 0);
                $('#hhh_cbtn_num').text(`${curr_rcmd_box_num+1}/${rcmd_box_data.length}`);
                $('.rcmd-box').find('.video-card-reco').each(function(i){
                    $(this).empty().append($(rcmd_box_data[curr_rcmd_box_num]).find('.video-card-reco:eq('+i+')>div').clone());
                })
            })
            cbtn_h += $cbtn_zuo.outerHeight()-1;

            //right
            $('.rcmd-box-wrap').append($new_cbtn.clone().attr('id','hhh_cbtn_you').css({height:'auto', top:`${h+1+cbtn_h}px`, 'border-top':'0px'})
                                                                                  .css({'border-top':'0px', 'border-top-left-radius':'0px', 'border-top-right-radius':'0px'})
                                                                                  .append('<i class="bilifont bili-icon_caozuo_xiangyou"></i>'));
            let $cbtn_you = $('#hhh_cbtn_you');
            $cbtn_you.click(function(){
                let $i = $(this).find('i');
                $i.addClass('active');
                setTimeout(function(){ $i.removeClass('active') },500);
                //恢复后一个list
                curr_rcmd_box_num = Math.min(curr_rcmd_box_num+1, rcmd_box_data.length-1);
                $('#hhh_cbtn_num').text(`${curr_rcmd_box_num+1}/${rcmd_box_data.length}`);
                $('.rcmd-box').find('.video-card-reco').each(function(i){
                    $(this).empty().append($(rcmd_box_data[curr_rcmd_box_num]).find('.video-card-reco:eq('+i+')>div').clone());
                })
            })
        }

        //初始化
        function init() {
            console.clear();
            let is_card_load = true;
            let is_content_load = true;
            let is_homepage_load = true;
            let is_history_break = null;
            let is_rcmd_box_break = null;
            new MutationObserver((mutations, observer) => {
                mutations.forEach(mutation => {
                    const target = mutation.target;
                    //typeof target.className === 'string' && target.className !== '' && log(target.className);
                    //log(window.location.href);
                    const stage = mutation.previousSibling && target.getAttribute('stage');
                    if(stage === '1' && $('.bilibili-player-video-wrap').length === 1){  //2.X
                        if($('#app').hasClass('app-v1')){
                            log("2.X“V3版”加载完毕");
                            bb_config.set_bb(BILI_2_X_V3);
                            run();
                        }else{
                            log("2.X“V2版”加载完毕");
                            bb_config.set_bb(BILI_2_X_V2);
                            run();
                        }
                    } else if(typeof target.className === 'string' && target.className === 'squirtle-fullscreen-wrap squirtle-block-wrap' && $('.bpx-player-video-area').length === 1) {  //3.X  pbp-tip
                        log("3.X加载完毕");
                        bb_config.set_bb(BILI_3_X);
                        run();
                    } else if(typeof target.className === 'string' && target.className==='bili-dyn-list__items' && is_content_load){
                        is_content_load = false;
                        log("2.X动态首页加载完毕");
                        run_content();
                        setTimeout(function() { is_content_load = true }, 200);
                    } else if(typeof target.className === 'string' && target.className === 'avatar' && target.baseURI.indexOf('www.bilibili.com/video/online.html') !== -1){
                        //log($('#hhh_online_list_style').length);
                        log("当前在线加载完毕");
                        run_preview();
                    } else if(typeof target.className === 'string' && target.className==='history-list'){
                        clearTimeout(is_history_break);
                        is_history_break = setTimeout(function() { log("历史记录加载完毕"); run_history()}, 200);
                    } else if(typeof target.className === 'string' && window.location.href.match(/https?:\/\/www.bilibili.com\/?$/) && is_homepage_load){
                        log("推荐列表加载完毕");
                        is_homepage_load = false;
                        run_rcmd_box();
                        //clearTimeout(is_rcmd_box_break);
                        //is_rcmd_box_break = setTimeout(function() { log("推荐列表加载完毕"); run_rcmd_box()}, 50);
                    // } else if(is_card_load === false && typeof target.className === 'string' && target.className === 'card' && $(target).find('.video-container .content').length){
                        // is_card_load = true;
                        // log("2.X动态首页加载完毕");
                        // run_card();  //搞笑,刚写完,2.70.7就有了
                        // removeMostViewedListener(config.getCheckboxSettingStatus('removeMostViewedListener'));
                    }
                });
            }).observe(document.body, {
                childList: true,
                subtree: true,
            });
        }

        init();
    }
}

hhh_lightoff_main.init();