// ==UserScript== // @name 哔哩哔哩(B站, bilibili)播放界面和部分操作优化 // @description B站播放器速度自定义(0.25 ~ 3), 支持快捷键(z:正常, x:减少速度, c:增加速度), 鼠标中键切换全屏等 // @namespace bili // @version 1.6.9 // @author vizo // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js // @include *://www.bilibili.com/video* // @include *://www.bilibili.com/bangumi* // @include *://www.bilibili.com/medialist/play* // @include https://search.bilibili.com* // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @run-at document-end // @noframes // @downloadURL none // ==/UserScript== GM_addStyle(` html { overflow-y: scroll; } html.hideScroll { overflow: hidden; margin-left: -3px; } body::-webkit-scrollbar { width: 6px; } body::-webkit-scrollbar-corner, body::-webkit-scrollbar-track { background-color: #f8f8f8; } body::-webkit-scrollbar-thumb { background: #c5c5c5; } #bilibili-player { position: relative; } #spsy_msg { width: 105px; height: 42px; text-align: center; line-height: 42px; border-radius: 4px; background: rgba(255,255,255,.8); color: #222; font-size: 16px; position: absolute; top: -80px; right: 0; bottom: 0; left: 0; margin: auto; z-index: 99999; pointer-events: none; display: none; } #bl_info_xz { height: 25px; line-height: 25px; font-size: 14px; padding: 0 5px; color: #00a1d6; position: absolute; top: -25px; right: 0; z-index: 2; } .bilibili-player-video-btn-volume, .bilibili-player-video-btn-speed { opacity: 0.4; pointer-events: none; } .bilibili-player-volumeHint { display: none !important; } .so-fg5r { } .so-fg5r .inp { width: 50px; color: #666; border: 1px solid #0ad; border-radius: 2px; padding: 2px 5px; outline: none; } .so-fg5r .inp:focus { border-color: #0ad; } .so-fg5r span { color: #666; } .video-item.hide_7s { display: none !important; } `) const G = { timer1s: 0, timer2s: 0, timer3s: 0, focusChangeTime: 0, g2URL: '', } const R = { timeout(ms = 0) { return new Promise(resolve => setTimeout(resolve, ms)) }, round(val, n = 2) { return Number(`${Math.round(`${val}e${n}`)}e-${n}`) }, floor(val, n = 2) { return Number(`${Math.floor(`${val}e${n}`)}e-${n}`) }, loadEl(fnz, timeout = 30e3) { return new Promise(resolve => { const iFn = () => { let el = typeof fnz === 'function' ? fnz() : $(fnz) if (el.length) { return resolve(el) } setTimeout(iFn, 50) } iFn() setTimeout(() => { return resolve($(null)) }, timeout) }) }, watchDom(el, ...args) { if (typeof el === 'string') { el = document.querySelector(el) } let opt = args.length > 1 ? args[0] : {} let cb = args.length > 1 ? args[1] : args[0] return new MutationObserver((mutations, observer) => { cb(mutations) }).observe(el, Object.assign({ childList: true, attributes: true, characterData: true, subtree: true, }, opt)) }, async getVideoWrap() { return (await R.loadEl('#bilibiliPlayer'))[0] }, async getVideo() { return (await R.loadEl(`#${(await R.getVideoWrap()).id} video`))[0] }, async appendMsgLay() { let wp = await R.getVideoWrap() let msg = document.getElementById('spsy_msg') if (!wp.contains(msg)) { wp.insertAdjacentHTML('beforeend', `
`) } }, async appendAxInfo() { let wp = await R.getVideoWrap() let inf = document.getElementById('bl_info_xz') if (!wp.contains(inf)) { wp.insertAdjacentHTML('beforeend', ``) } }, setAxInfo() { let inf = $('#bl_info_xz') let vol = Math.trunc(R.getGMvolume() * 100) let speed = R.getGMspeed() if (inf.length) { speed = speed === 1 ? speed : `${speed}` inf.html(`速度: ${speed} 音量: ${vol}`) } }, toggleVideoFullscreen() { $('.bilibili-player-video-btn-fullscreen')[0].click() }, setGMspeed(val) { return GM_setValue('--> bl_player_speed', val) }, setGMvolume(val) { GM_setValue('--> bl_player_volume', val) }, getGMspeed() { return +GM_getValue('--> bl_player_speed') || 1 }, getGMvolume() { let vol = GM_getValue('--> bl_player_volume') return vol !== undefined ? vol : 0.5 }, // 判断是否全屏 isFullScreen() { return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen }, // 显示信息 showSpMsg(msg, type = '速度') { let mp = $('#spsy_msg') clearTimeout(G.timer2s) mp.fadeIn(180) mp.text(`${type} ${msg}`) G.timer2s = setTimeout(() => { mp.fadeOut(350) }, 800) }, // 设置播放器播放速度 async setPlayerSpeed(speedVal = R.getGMspeed()) { let video = await R.getVideo() video.playbackRate = speedVal R.setGMspeed(speedVal) R.setAxInfo() }, // 设置音量 async setVolume(vol = R.getGMvolume()) { let video = await R.getVideo() video.volume = vol R.setGMvolume(vol) R.setAxInfo() }, initVideoCfg() { clearTimeout(G.timer3s) G.timer3s = setTimeout(() => { R.appendMsgLay() R.appendAxInfo() R.setPlayerSpeed() R.setVolume() }, 10) }, debounce(func, delay) { let timer = null return function() { timer && clearTimeout(timer) timer = setTimeout(() => { func.apply(this, arguments) }, delay) } }, zTimer() { R.initVideoCfg() setTimeout(R.zTimer, 2000) }, async regWpMouseEvt() { const wwp = $('#playerWrap') const wp = wwp.length ? wwp : await R.getVideoWrap() $(wp).on('mouseenter', () => { $('html').addClass('hideScroll') }) $(wp).on('mouseleave', () => { $('html').removeClass('hideScroll') }) }, watchUrlFunc() { if (G.g2URL !== location.href) { G.g2URL = location.href R.eachSearchResultAndAddHideCls() } setTimeout(R.watchUrlFunc, 500) }, judgeIsAppendSoMod() { const html = `