斗鱼(douyu)快捷操作__

滚轮音量调节;鼠标功能键全屏;快捷键:开关弹幕D、网页全屏W、隐藏有边框Q、↑↓键音量调节等

// ==UserScript==
// @name         斗鱼(douyu)快捷操作__
// @namespace    hhh2000
// @version      0.4.4
// @description  滚轮音量调节;鼠标功能键全屏;快捷键:开关弹幕D、网页全屏W、隐藏有边框Q、↑↓键音量调节等
// @author       hhh2000
// @match        http*://www.douyu.com/*dyshid*
// @match        http*://www.douyu.com/*topic*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js
// @run-at       document-end
// @grant        none
// @compatible   chrome
/* globals jQuery, $, waitForkeyElements */
/* eslint-disable no-multi-spaces, dot-notation */
/* eslint no-eval:0 */
// ==/UserScript==

'use strict';
(function() {
    let log = console.log
    let err = console.error

    // log = ()=>{}

    log(location.href)

    // const key = 'hasRunOnce_' + location.hostname
    // if (!GM_getValue(key, false)) {
    //     GM_setValue(key, true)
    //     // ✅ 这里写你只想运行一次的逻辑
    //     console.log('✅ 脚本第一次运行')
    // } else {
    //     console.log('⏭️ 脚本已运行过,跳过')
    //     return
    // }


    function getkeyCode(k) {
        var keyCodes = {
            300: '滚↑轮',
            301: '滚↓轮',
            302: '鼠标左键',
            303: '鼠标右键',
            304: '鼠标中键',
            305: '鼠标左前侧键',
            306: '鼠标左后侧键',
            307: '鼠标右前侧键',
            308: '鼠标右后侧键',
            309: '鼠标中前侧键',
            310: '鼠标中后侧键',

            0: "",
            3: "break",
            8: "Backspace",
            9: "Tab",
            12: "Clear",
            13: "Enter",
            16: "Shift",
            17: "Ctrl",
            18: "Alt",
            19: "PauseBreak",
            20: "CapsLock",
            27: "Escape",
            32: "Space",
            33: "PageUp",
            34: "PageDown",
            35: "End",
            36: "Home",
            37: "←",   //LeftArrow ↑ ↓ ← →
            38: "↑",   //UpArrow
            39: "→",   //RightArrow
            40: "↓",   //DownArrow
            45: "Insert",
            46: "Delete",
            48: "0",
            49: "1",
            50: "2",
            51: "3",
            52: "4",
            53: "5",
            54: "6",
            55: "7",
            56: "8",
            57: "9",
            65: "A",
            66: "B",
            67: "C",
            68: "D",
            69: "E",
            70: "F",
            71: "G",
            72: "H",
            73: "I",
            74: "J",
            75: "K",
            76: "L",
            77: "M",
            78: "N",
            79: "O",
            80: "P",
            81: "Q",
            82: "R",
            83: "S",
            84: "T",
            85: "U",
            86: "V",
            87: "W",
            88: "X",
            89: "Y",
            90: "Z",
            93: "ContextMenu",
            96: "NumPad0",
            97: "NumPad1",
            98: "NumPad2",
            99: "NumPad3",
            100: "NumPad4",
            101: "NumPad5",
            102: "NumPad6",
            103: "NumPad7",
            104: "NumPad8",
            105: "NumPad9",
            106: "NumPad_Multiply",
            107: "NumPad_Add",
            108: "NumPad_Separator",
            109: "NumPad_Subtract",
            110: "NumPad_Decimal",
            111: "NumPad_Divide",
            112: "F1",
            113: "F2",
            114: "F3",
            115: "F4",
            116: "F5",
            117: "F6",
            118: "F7",
            119: "F8",
            120: "F9",
            121: "F10",
            122: "F11",
            123: "F12",
            124: "F13",
            125: "F14",
            126: "F15",
            127: "F16",
            128: "F17",
            129: "F18",
            130: "F19",
            144: "NumLock",
            145: "ScrollLock",
            166: "BrowserBack",
            167: "BrowserForward",
            170: "BrowserSearch",
            172: "BrowserHome",
            173: "AudioVolumeMute",
            174: "AudioVolumeDown",
            175: "AudioVolumeUp",
            176: "MediaTrackNext",
            177: "MediaTrackPrevious",
            178: "MediaStop",
            179: "MediaPlayPause",
            180: "LaunchMail",
            181: "LaunchMediaPlayer",
            183: "LaunchApp2",
            186: ";",
            187: "=",
            188: ",",
            189: "-",
            190: ".",
            191: "/",
            192: "`",
            193: "ABNT_C1",
            194: "ABNT_C2",
            219: "[",
            220: "\\",
            221: "]",
            222: "'",
            223: "OEM_8",
            226: "OEM_102",
            229: "KeyInComposition",
        };
        return keyCodes[k];
    }
    let keycode = {
        'Enter': 13,
        'Ctrl': 17,
        'Esc': 27,
        'left': 37,
        'right': 39,
        'up': 38,
        'down': 40,
        'space': 32,
        'NumPad0': 96,
        'NumPad_Decimal': 110,
    }

    function set_progress(selector, curr_percent, inc_percent, limit_begin, limit_end){

        function calc_bar_offset(percent, bar_length, limit_begin, limit_end){
            let p = Math.max(Math.min(+percent, limit_end), limit_begin);
            let limit = limit_end - limit_begin;
            let bar_offset = (p-limit_begin) * bar_length / limit;
            //log(p, limit, bar_length, 128/100*p, bar_offset)
            return bar_offset;  //百分比对应进度条位置
        }

       // $('.controlbar-f41e38').removeClass('hide-6cf943')

        let e1 = new MouseEvent('mousedown'), e2 = new MouseEvent('mouseup')
        // log(selector)
        let rect = selector.getBoundingClientRect()

        let padding_top = +$(selector).css('padding-top').match(/\d+/)?.[0]
        let padding_bottom = +$(selector).css('padding-bottom').match(/\d+/)?.[0]
        let bar_offset = calc_bar_offset(curr_percent-inc_percent, (rect.height-padding_top-padding_bottom), limit_begin, limit_end)
        let clientY = rect.bottom - padding_bottom - bar_offset + 1

        let o1 = calc_bar_offset(curr_percent, (rect.height-padding_top-padding_bottom), limit_begin, limit_end)
        let o2 = calc_bar_offset(curr_percent+inc_percent, (rect.height-padding_top-padding_bottom), limit_begin, limit_end)
        let o3 = calc_bar_offset(curr_percent-inc_percent, (rect.height-padding_top-padding_bottom), limit_begin, limit_end)
        // log(`当前音量:${curr_percent}   加音量${curr_percent+inc_percent}   减音量${curr_percent-inc_percent}`)
        // log(`当前距离:${o1}   加距离${o2}   减距离${o3}`)

        let percent = Math.max(Math.min(curr_percent - inc_percent, limit_end), limit_begin)
        let step = (rect.height-padding_top-padding_bottom)/(limit_end - limit_begin)/2
        // 动态调整
        for(let i=0; i<Math.abs(inc_percent*10); ++i){
            //log(`------音量:${i}------`)
            //log(`原音量:${curr_percent}/${parseInt($('.tips-3df825').text().match(/\d+/))}`)
            e1.initMouseEvent('mousedown',1,1,window,1,0,0,0,clientY,0,0,0,0,0,null);
            e2.initMouseEvent('mouseup'  ,1,1,window,1,0,0,0,clientY,0,0,0,0,0,null);
            selector.dispatchEvent(e1); selector.dispatchEvent(e2);

            let next_percent = parseInt($('.tips-3df825').text().match(/\d+/))
            //log(`新音量:${percent}/${next_percent}/${$('.tips-3df825').text().match(/\d+/)}`)

            //log(`原音量:${percent} 新音量:${next_percent} 增减音量:${inc_percent} clientY: ${clientY} step: ${step}`)
            if(percent == next_percent) break
            else if(inc_percent > 0 && percent < next_percent) clientY += step
            else if(inc_percent < 0 && percent > next_percent) clientY -= step
            else break

        }
    }

    function adjust_progress(selector_str, inc_percent, range_bengin, range_end){
        //new
        // let container   = document.querySelector('.player__jsy1T');
        // container.classList.add('in__HeN9a', 'player-is-hover'); // 方便加样式
        // let volumeBar   = document.querySelector('.VolumeBar-164ea4');
        // volumeBar.classList.add('active-a5d033'); // 方便加样式

        // log(window.location.href)
        if(window.location.href.includes('www.douyu.com/beta/') === true){
            // log('===new===');
            function set_percent(percent) {
                percent = Math.max(0, Math.min(100, percent))
                // log(2,percent)
                let back = $('.volume-07c230 .back-85f312')[0]
                let rect = back.getBoundingClientRect()
                let clientY = rect.bottom - percent
                const e1 = new MouseEvent('mousedown', {
                    bubbles: true,
                    cancelable: true,
                    view: window,
                    detail: 0,
                    screenX: 0,
                    screenY: 0,
                    clientX: 0,
                    clientY: clientY,
                    ctrlKey: false,
                    altKey: false,
                    shiftKey: false,
                    metaKey: false,
                    button: 0,
                    relatedTarget: null
                })
                const e2 = new MouseEvent('mouseup', {
                    bubbles: true,
                    cancelable: true,
                    view: window,
                    detail: 0,
                    screenX: 0,
                    screenY: 0,
                    clientX: 0,
                    clientY: clientY,
                    ctrlKey: false,
                    altKey: false,
                    shiftKey: false,
                    metaKey: false,
                    button: 0,
                    relatedTarget: null
                })
                back?.dispatchEvent(e1); back?.dispatchEvent(e2);
            }

            const $box  = $('.volume-07c230');
            const $front = $box?.find('.front-99e2aa');
            const $point = $box?.find('.point-6ef744');
            const $label = $box?.find('.tips2-9bb064');
            const $tip   = $box?.find('.tips-d0d0f1');
            if ($front.length <= 0) return;

            let volumeBar = document.querySelector('.VolumeBar-164ea4');
            let e1 = new MouseEvent('mouseover'), e2 = new MouseEvent('mouseout')
            e1.initMouseEvent('mouseover',1,1,window,1,0,0,0,0,0,0,0,0,0,null)
            volumeBar?.dispatchEvent(e1)

            const curr_percent = parseInt($tip.text().match(/\d+/))  //tips-d0d0f1 - tips2-9bb064
            // log('1:',curr_percent, parseInt(inc_percent))
            // set_percent(parseInt(curr_percent) - parseInt(inc_percent))
            set_percent(curr_percent - parseInt(inc_percent))

//             $tip.css({ visibility: 'visible', opacity: 1 })

//             let t = $box.data('hhh_timeout')
//             clearTimeout(t)
//             t = setTimeout(()=>{
//                 $tip.css({ visibility: 'hidden', opacity: 0 })
//                 e2.initMouseEvent('mouseout',1,1,window,1,0,0,0,0,0,0,0,0,0,null)
//                 volumeBar?.dispatchEvent(e2)
//             }, 1000)
//             $box.data('hhh_timeout', t)

            // let timer

            // $tip[0].style.visibility = 'visible';
            // $tip[0].style.opacity = '1';
            // clearTimeout(timer);
            // timer = setTimeout(() => {
            //     $tip[0].style.transition = 'opacity .3s';
            //     $tip[0].style.opacity = '0';
            //     setTimeout(() => $tip[0].style.visibility = 'hidden', 300);
            //     volumeBar.classList.remove('active-a5d033')
            // }, 1000)

//             const MAX = range_end - range_bengin           // 滑条最大 px 高度
//             let vol = 20

//             /* 更新 UI 并显示提示 */
//             const setVol = v => {

//                 let vol = Math.max(0, Math.min(100, v));
//                 const h = (vol / 100) * MAX;
//                 front.style.height = `${h}px`;
//                 point.style.bottom = `${h + 7}px`;
//                 label.textContent = `音量${vol}%`;
//                 //
//                 let rect = point.getBoundingClientRect()
//                 let clientY = rect.bottom
//                 const e1 = new MouseEvent('mousedown', {
//                     bubbles: true,
//                     cancelable: true,
//                     view: window,
//                     detail: 0,
//                     screenX: 0,
//                     screenY: 0,
//                     clientX: 0,
//                     clientY: clientY,
//                     ctrlKey: false,
//                     altKey: false,
//                     shiftKey: false,
//                     metaKey: false,
//                     button: 0,
//                     relatedTarget: null
//                 })
//                 const e2 = new MouseEvent('mouseup', {
//                     bubbles: true,
//                     cancelable: true,
//                     view: window,
//                     detail: 0,
//                     screenX: 0,
//                     screenY: 0,
//                     clientX: 0,
//                     clientY: clientY,
//                     ctrlKey: false,
//                     altKey: false,
//                     shiftKey: false,
//                     metaKey: false,
//                     button: 0,
//                     relatedTarget: null
//                 })
//                 // let e1 = new MouseEvent('mousedown'), e2 = new MouseEvent('mouseup')
//                 // e1.initMouseEvent('mousedown',1,1,0,window,0,0,0,clientY,0,0,0,0,0,null);
//                 // e2.initMouseEvent('mouseup'  ,1,1,0,window,0,0,0,clientY,0,0,0,0,0,null);
//                 point?.dispatchEvent(e1); point?.dispatchEvent(e2);
//                 log('2',v, vol, parseInt($('.tips-d0d0f1').text().match(/\d+/)), clientY)

//                 $tip[0].style.visibility = 'visible';
//                 $tip[0].style.opacity = '1';
//                 clearTimeout(timer);
//                 timer = setTimeout(() => {
//                     tip.style.transition = 'opacity .3s';
//                     tip.style.opacity = '0';
//                     setTimeout(() => tip.style.visibility = 'hidden', 300);
//                     volumeBar.classList.remove('active-a5d033')
//                 }, 1000)
//             }

//             const curr_percent = parseInt($('.tips-d0d0f1').text().match(/\d+/))  //tips-d0d0f1 - tips2-9bb064
//             log(inc_percent, curr_percent)
//             setVol(curr_percent - (inc_percent < 0 ? -5 : 5))

            /* 绑定滚轮 */
            // document.querySelector('#__h5player').addEventListener('wheel', e => {
            //     e.preventDefault();
            //     // setVol(vol + (e.deltaY < 0 ? 5 : -5));
            //     log(e, inc_percent)
            //     setVol(vol + (e.deltaY < 0 ? 1 : -1));
            // });
        }else{  //old
            let e1 = new MouseEvent('mouseover'), e2 = new MouseEvent('mouseout')
            e1.initMouseEvent('mouseover',1,1,window,1,0,0,0,0,0,0,0,0,0,null)
            $('.volume-8e2726')?.[0]?.dispatchEvent(e1)
            $('.volume-silent-3eb726')?.[0]?.dispatchEvent(e1)
            //$('.VolumeBar-9010af').css('visibility', 'hidden')

            let selector = $(selector_str)[0] //VolumeBar-164ea4
            const curr_percent = parseInt($('.tips-3df825').text().match(/\d+/))  //tips-d0d0f1

            set_progress(selector, curr_percent, parseInt(inc_percent), 0, 100)
            $('.tips-3df825').css({'visibility': 'visible'})

            // $('.VolumeBar-9010af').css('visibility', 'visible')
            let t = $('.volume-bar-06542d').data('hhh_timeout')
            clearTimeout(t)
            t = setTimeout(()=>{
                e2.initMouseEvent('mouseout',1,1,window,1,0,0,0,0,0,0,0,0,0,null)
                $('.volume-8e2726')?.[0]?.dispatchEvent(e2)
                $('.volume-silent-3eb726')?.[0]?.dispatchEvent(e2)
            }, 1000)
            $('.volume-bar-06542d').data('hhh_timeout', t)
        }
    }

    //显示hint XXX
    function cut_InfoDisappear(){
        if($('.kui-message-information-item').css('animation-name') === 'InfoDisappear'){
            $('.kui-message-information-item').css('animation-name', 'InfoDisappear1')
        }else{
            $('.kui-message-information-item').css('animation-name', 'InfoDisappear')
        }
    }


    function waitForTrue(ifTrue, callback, time=100) {
        // log($('#player-control-video').length)
        // log(document.querySelectorAll('#__h5player').length)
        //log(ifTrue())
        if(--time < 0) {err('waitForTrue 超时 '+ifTrue); return false;}
        const fn = waitForTrue;
        //let fn = arguments.callee;
        if (ifTrue()) {
            callback(); return true;
        } else {
            setTimeout(function() { fn(ifTrue, callback, time); }, 50);
        }
    }

    //滚轮音量调节;鼠标功能键全屏;快捷键:开关弹幕D、网页全屏W、隐藏有边框Q、↑↓键音量调节
    function run(){


        log('douyu快捷操作加载完毕')

        $('.ActBase').hide()

        //非全屏滚轮音量调节
        $('#__h5player').off('wheel.hhh_douyu').on('wheel.hhh_douyu',function(e){
            let delta = e.originalEvent.wheelDelta
            // log(delta, e)
            if(delta >= 0){  //up
                adjust_progress('.volume-bar-06542d', -1, 0, 100)  //volume-bar-06542d
            }else{
                adjust_progress('.volume-bar-06542d',  1, 0, 100)
            }
            e.preventDefault();
            return false
        })

        //功能键全屏
        $('#__h5player').off('mousedown.hhh_douyu').on('mousedown.hhh_douyu',function(e){
            if(e.buttons > 2){
                $('.wfs-2a8e83, .wfs-exit-180268').not('.removed-9d4c42').click()
                return false
            }
        })

        //快捷键
        $('body').off('keydown.hhh_douyu').on('keydown.hhh_douyu',function(e){
            // log(e.keyCode, e)
            if(e.keyCode === keycode['up'] || e.keyCode === keycode['down']){  //↑↓音量
                if(e.keyCode === keycode['up']){
                    adjust_progress('.volume-bar-06542d', -5, 0, 100)
                }else{
                    adjust_progress('.volume-bar-06542d',  5, 0, 100)
                }
                //$('.kui-message-information-text font').text($('#volume-tip').text())  //set hint text
                //cut_InfoDisappear()
                return false
            }else if(e.keyCode === keycode['NumPad_Decimal'] || e.keyCode === keycode['NumPad0']){  //NumPad_Decimal numpad1 音量
                // log(e.target.className, e.target.nodeName, $(e.target).attr('type'))
                // log(e.originalEvent.path[0].nodeName)
                // log($(e.originalEvent.path[0]).attr('type'))
                let classnames = /editor/
                let nodenames = ['INPUT', 'TEXTAREA']
                let target_classnames = e.target.className
                let target_nodename = e.target.nodeName
                if(nodenames.includes(target_nodename) === false && target_classnames.match(classnames) === null){  //排除发送弹幕等情况
                    if(e.keyCode === keycode['NumPad_Decimal']){
                        adjust_progress('.volume-bar-06542d', -1, 0, 100)
                    }else{
                        adjust_progress('.volume-bar-06542d',  1, 0, 100)
                    }
                    return false
                }
            }else if(e.keyCode === 'W'.charCodeAt()){  //W 网页全屏
                $('.wfs-2a8e83, .wfs-exit-180268').not('.removed-9d4c42').click()
            }else if(e.keyCode === 'F'.charCodeAt()){  //W 全屏
                $('.fs-781153, .fs-exit-b6e6a7').not('.removed-9d4c42').click()
            }else if(e.keyCode === 'Q'.charCodeAt()){  //W 隐藏右边框
                $('.layout-Player-asidetoggleButton').click()
            }else if(e.keyCode === 'D'.charCodeAt()){  //D 开关弹幕
                $('.showdanmu-42b0ac, .hidedanmu-5d54e2').not('.removed-9d4c42').click()
                $('.showdanmuWrap-9c22cd>.icon-c8be96').click()
            }
        })
    }

    waitForTrue(()=>$('#player-control-video').length>0, ()=>{
        run()
    })

})();