Greasy Fork

Greasy Fork is available in English.

哔哩哔哩(B站bilibili)-播放速度及部分操作优化

B站播放器速度自定义(0.25 ~ 3), 支持快捷键(z:正常, x:减少速度, c:增加速度), 支持多标签窗口速度同步, 鼠标中键切换全屏

当前为 2019-12-01 提交的版本,查看 最新版本

// ==UserScript==
// @name         哔哩哔哩(B站bilibili)-播放速度及部分操作优化
// @description  B站播放器速度自定义(0.25 ~ 3), 支持快捷键(z:正常, x:减少速度, c:增加速度), 支持多标签窗口速度同步, 鼠标中键切换全屏
// @namespace    bili
// @version      1.2
// @author       vizo
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @include      *://www.bilibili.com/video*
// @include      *://www.bilibili.com/bangumi*
// @run-at       document-end
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @noframes
// ==/UserScript==
'use strict'

GM_addStyle(`
  html {
    overflow-y: scroll;
  }
  body.hideScroll {
    overflow-y: hidden !important;
  }
  #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: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    z-index: 985;
    pointer-events: none;
    display: none;
  }
`)

let timer2s = null

$(function() {
  let TIMER = null
  
  const timeout = (ms) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve()
      }, ms)
    })
  }
  
  const appendMsgLay = async () => {
    let v_warp = $('.bilibili-player-video-wrap')
    let s_msg = v_warp.find('#spsy_msg')
    let speedMsg = `<div id="spsy_msg"></div>`
    if (v_warp.length) {
      if(!s_msg.length) {
        v_warp.append(speedMsg)
      }
    } else {
      await timeout(200)
      appendMsgLay()
    }
  }
  
  const setPlayerSpeed = ( speed = getGmSpeed() ) => {
    appendMsgLay()
    
    let video = $('.bilibili-player-video video')
    video[0].playbackRate = speed
    let store = JSON.parse( getSSsetingCfg() )
    store.video_status.videospeed = speed
    sessionStorage.setItem('bilibili_player_settings', JSON.stringify(store))
  }
  
  const toggleVideoFullscreen = async () => {
    let video = $('.bilibili-player-video video')
    if (video.length) {
      $('.bilibili-player-video-btn-fullscreen')[0].click()
    } else {
      await timeout(100)
      toggleVideoFullscreen()
    }
  }
  
  const getGmSpeed = () => {
    return +GM_getValue('bl_player_speed') || 1
  }
  
  const getSSsetingCfg = () => {
    return sessionStorage.getItem('bilibili_player_settings')
  }
  
  const getLSsetingCfg = () => {
    return localStorage.getItem('bilibili_player_settings')
  }
  
  const setGmSpeed = (val) => {
    GM_setValue('bl_player_speed', val)
  }
  
  const showSpMsg = (msg, type = '速度') => {
    let mp = $('#spsy_msg')
    clearTimeout(TIMER)
    mp.fadeIn(180)
    mp.text(`${type} ${msg}`)
    
    TIMER = setTimeout(() => {
      mp.fadeOut(250)
    }, 800)
  }
  
  $('body').on('keyup', function(e) {
    let vol = +(GM_getValue('bl_player_volume') || video[0].volume)
    let upKey = e.keycode === 38
    let downKey = e.keycode === 40
    if (upKey || downKey) {
      if (upKey) {
        vol = Math.min(vol + 0.05, 1)
      } else {
        vol = Math.max(vol + 0.05, 0)
      }
      GM_setValue('bl_player_volume', vol)
    }
  })
  
  // 右键菜单设置播放速度
  $('body').on('click', '.bilibili-player-contextmenu-subwrapp span', function() {
    let tis = $(this)
    let rate = tis.attr('data-rate')
    setGmSpeed(rate)
    return false
  })
  
  // 滚轮点击切换全屏
  $('body').on('mousedown', '.bilibili-player-video-wrap', function(e) {
    if (e.button === 1) {
      e.preventDefault()
      toggleVideoFullscreen()
    }
  })
  
  $('body').on('mousedown', function(e) {
    if (e.button === 1) {
      e.preventDefault()
    }
  })
  
  // 键盘快捷键设置播放速度
  $('body').on('keyup', function(e) {
    if (/^[zxc]$/.test(e.key) && !e.ctrlKey && !e.altKey) {
      if (e.target.nodeName !== 'BODY') return
      
      let val = getGmSpeed()
      if (e.key === 'z') {
        val = 1
      }
      if (e.key === 'x') {
        val = Math.max(val - 0.25, 0.25)
      }
      if (e.key === 'c') {
        val = Math.min(val + 0.25, 3)
      } 
      setGmSpeed(val)
      showSpMsg(val)
    }
  })
  
  // 滚轮调节音量
  $('body').on('mousewheel', '.bilibili-player-video video', function() {
    let video = $(this)
    if (!video.length) return
    
    let store = getLSsetingCfg() ? JSON.parse( getLSsetingCfg() ) : null
    let st_vol = store ? (store.video_status.volume || 0.01) : null
    
    let vol = +(st_vol || GM_getValue('bl_player_volume') || video[0].volume)
    if (event.wheelDelta > 0) {
      vol = Math.min(vol + 0.02, 1)
    } else {
      vol = Math.max(vol - 0.02, 0)
    }
    store.video_status.volume = vol
    localStorage.setItem('bilibili_player_settings', JSON.stringify(store))
    
    GM_setValue('bl_player_volume', vol)
    
    video[0].volume = vol
    
    let pVol = Math.round(vol * 100) + '%'
    showSpMsg(pVol, '音量')
  })
  
  $('body').on('mouseenter', '.bilibili-player-video', function() {
    let tis = $(this)
    $('body').addClass('hideScroll')
    tis.on('mouseleave', function() {
      $('body').removeClass('hideScroll')
    })
    
  })
  
  setInterval(setPlayerSpeed, 500)
})