🏠 Home 

B站上单播放器 Mongolian Player

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()
})();