B站播放器优化。添加了一些 youtube 和 potplayer 的快捷键。修复了多P连播,增加了自动播放记忆位置等功能。
// ==UserScript== // @name B站上单播放器 Mongolian Player // @version 0.1.3 // @description B站播放器优化。添加了一些 youtube 和 potplayer 的快捷键。修复了多P连播,增加了自动播放记忆位置等功能。 // @author Erimus // @include http*.bilibili.com/video/* // @include http*.bilibili.com/bangumi/play/* // @namespace https://greasyfork.org/users/46393 // ==/UserScript== /* 功能说明 ==================== 快捷键 a: 全屏(f 优先给 vim 用) w: 网页全屏 t: 宽屏 i: 画中画 d: 弹幕开关 双击: 切换全屏 m: 静音 c: 播放加速 每次10% v: 播放减速 每次10%(x 优先给 vim 用) z: 播放恢复原速 0 ~ 9: 切换到相应的百分比进度(如按2等于跳到20%进度) shift + right: 下一P ==================== 其它功能 - 多 P 自动连播(不会自动播放推荐视频) - 自动跳转到上次记录的播放位置 - 开播自动网页全屏 * 这个是我个人使用习惯,有单独一个chrome窗口在副屏播放视频。 * 如不需要的可以自行注释掉底部相关代码。 ==================== B站本就支持的(也许有人不知道的)功能 f: 全屏 [: 上一P ]: 下一P 自动开播: 可以在播放器设置里开启(非自动切集) */ // 在播放器获得焦点时,B站默认有一个快解键F可以切换全屏。 (function() { 'use strict'; const SN = '[B站上单播放器]' // script name console.log(SN, '油猴脚本开始') // 监听页面跳转事件 let _wr = (type) => { let orig = history[type + SN] return () => { let rv = orig.apply(this, arguments), e = new Event(type + SN) e.arguments = arguments window.dispatchEvent(e) return rv } } history.pushState = _wr('pushState') history.replaceState = _wr('replaceState') let videoObj // 播放器元素 // 缩写 let find = (selector) => { return document.querySelector(selector) } let find_n_click = (selector) => { find(selector).click() } // 按键快捷键 let eleDict = { 'fullscreen': '.bilibili-player-video-btn-fullscreen', //全屏 'webFullscreen': '.bilibili-player-video-web-fullscreen', //网页全屏 'theaterMode': '.bilibili-player-video-btn-widescreen', //宽屏 'miniPlayer': '.bilibili-player-video-btn-pip', //画中画 'mute': '.bilibili-player-iconfont-volume', //静音 'danmaku': '.bilibili-player-video-danmaku-switch>input', //弹幕开关 'playNext': '.bilibili-player-iconfont-next', //播放下一P 'playerWrapper': '.bilibili-player-video-wrap', //播放器可双击区域 } // 番剧模式下 播放器元素名称不同 if (document.URL.indexOf('bangumi/play') != -1) { eleDict.fullscreen = '.squirtle-video-fullscreen' //全屏 eleDict.webFullscreen = '.squirtle-pagefullscreen-inactive' //网页全屏 eleDict.theaterMode = '.squirtle-video-widescreen' //宽屏 eleDict.miniPlayer = '.squirtle-video-pip' //画中画 eleDict.mute = '.squirtle-volume-mute' //静音 eleDict.danmaku = '.bpx-player-dm-switch input' //弹幕开关 eleDict.playNext = '.squirtle-video-next' //播放下一P eleDict.playerWrapper = '.bpx-player-video-wrap' //播放器可双击区域 } const shortcutDict = { 'a': eleDict.fullscreen, //全屏 'w': eleDict.webFullscreen, //网页全屏 't': eleDict.theaterMode, //宽屏 'i': eleDict.miniPlayer, //画中画 'm': eleDict.mute, //静音 'd': eleDict.danmaku, //弹幕开关 } let pressKeyborder = function(e) { if (e && e.key) { console.debug(SN, 'e:', e) if (e.key in shortcutDict) { find_n_click(shortcutDict[e.key]) } else if (e.shiftKey && e.key == 'ArrowRight') { //shift+r 下一P find_n_click(eleDict.playNext) } else if (e.key === 'c') { //加速 videoObj.playbackRate += 0.1 } else if (e.key === 'v') { //减速 videoObj.playbackRate -= 0.1 } else if (e.key === 'z') { //重置速度 videoObj.playbackRate = 1 } else if ('1234567890'.indexOf(e.key) != -1) { //切进度条 videoObj.currentTime = videoObj.duration / 10 * parseInt(e.key) } } } let init = function() { // 寻找视频播放器 添加功能 let wait_for_video_player_init = setInterval(() => { console.debug(SN, 'Init:', document.URL) let click_area = find(eleDict.playerWrapper) videoObj = find('video:first-child') console.debug(SN, 'click_area:', click_area) console.debug(SN, 'videoObj:', videoObj) if (click_area && videoObj) { console.log(SN, '视频播放器加载完毕!') clearInterval(wait_for_video_player_init) // 双击切换全屏 click_area.addEventListener('dblclick', function(e) { e.stopPropagation() console.log(SN, '双击切换全屏') find_n_click(eleDict.fullscreen) }) } }, 500) // 添加快捷键监听 document.addEventListener('keydown', pressKeyborder); // 有些元素需要延迟载入 所以让它找一会儿 let addAutoPlayNext = false //自动分P 是否含有多P let jumpToSavedTime = false //进度记录 是否存有进度 let find_more = setInterval(() => { // 自动切P (自动播放关闭,当视频播放结束时自动按下一段按钮。) // B站自动切P现在会自动播放推荐视频,此处应有蒙古上单名言。 if (!addAutoPlayNext) { let nextBtn = find(eleDict.playNext) if (nextBtn) { setInterval(() => { if (videoObj.duration - videoObj.currentTime <= 0) { nextBtn.click() } }, 1000) addAutoPlayNext = true } } // 自动跳到上次播放位置 if (!jumpToSavedTime) { let continuedBtn = find('.bilibili-player-video-toast-item-jump') console.debug(SN, 'Continue Play Button:', continuedBtn) if (continuedBtn) { jumpToSavedTime = true // 不跳转到其它话(上次看到 xx章节) 只在当前视频中跳转进度 // 有时候没看片尾 会记录上一集的片尾位置之类的 let continuedText = find('.bilibili-player-video-toast-item-text').innerHTML console.debug(SN, 'Continue Text:', continuedText) if (continuedText.indexOf(' ') == -1) { continuedBtn.click() } } } }, 200) // 无论是否找到 10秒后都停止搜寻 setTimeout(() => { clearInterval(find_more) }, 10000) // 持续尝试 直到成功 let isFullScreen = false //自动网页全屏 当前是否全屏 let try_until_success = setInterval(() => { // 自动网页全屏 开始 if (!isFullScreen) { // check fullscreen status if (find(eleDict.playerWrapper).clientWidth == document.body.clientWidth) { console.log(SN, 'fullscreen OK') isFullScreen = true } else { find_n_click(eleDict.webFullscreen) } } // 自动网页全屏 结束(不需要的删掉这段) if (isFullScreen) { clearInterval(try_until_success) } }, 500) } init() })();