mirror of
https://github.com/the1812/Bilibili-Evolved.git
synced 2025-11-04 21:22:45 +08:00
Refactor keymap
This commit is contained in:
parent
333bb1b47f
commit
0887384456
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -25,6 +25,7 @@
|
||||
"Swiper",
|
||||
"Violentmonkey",
|
||||
"Vuex",
|
||||
"WASD",
|
||||
"Watchlater",
|
||||
"afterbegin",
|
||||
"afterend",
|
||||
|
||||
2
min/custom-navbar.min.js
vendored
2
min/custom-navbar.min.js
vendored
File diff suppressed because one or more lines are too long
1
min/key-bindings.min.js
vendored
Normal file
1
min/key-bindings.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
(()=>(e,t)=>{const n=["shift","alt","ctrl","meta"];const i=_.once((e=>{const t=document.URL.startsWith("https://www.bilibili.com/watchlater/");const i=document.URL.startsWith("https://www.bilibili.com/medialist/play/");const o={enable:true};document.body.addEventListener("keydown",(s=>{if(!o.enable){return}if(t&&document.URL.endsWith("list")){return}if(document.activeElement&&isTyping()){return}const r=s.key.toLowerCase();const l=dq(".bilibili-player-sphere-control");if(l!==null&&l.style.display!=="none"&&["w","a","s","d"].includes(r)){return}e.forEach((e=>{var o;const r=n.some((t=>{const n=e.keys.includes(t);const i=s[t+"Key"];return n!==i}));if(r){return}const l=e.keys.filter((e=>!n.includes(e.toLowerCase()))).map((e=>e.toLowerCase()));const c=l.includes(s.key.toLowerCase())||l.includes(s.code.toLowerCase());if(!c){return}if((o=e===null||e===void 0?void 0:e.prevent)!==null&&o!==void 0?o:true){s.stopPropagation();s.preventDefault()}e.action({binding:e,isWatchlater:t,isMediaList:i,event:s})}))}));return o}));return{export:{loadKeyBindings:i}}})();
|
||||
2
min/keymap.min.js
vendored
2
min/keymap.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
// ==UserScript==
|
||||
// @name Bilibili Evolved (Preview)
|
||||
// @version 1.11.8
|
||||
// @version 1.11.9
|
||||
// @description Bilibili Evolved 的预览版, 可以抢先体验新功能.
|
||||
// @author Grant Howard, Coulomb-G
|
||||
// @copyright 2020, Grant Howard (https://github.com/the1812) & Coulomb-G (https://github.com/Coulomb-G)
|
||||
|
||||
@ -250,6 +250,7 @@ export const settings = {
|
||||
rememberVideoSpeedList: {},
|
||||
rememberVideoSpeed: false,
|
||||
extendVideoSpeed: true,
|
||||
customKeyBindings: {},
|
||||
cache: {},
|
||||
}
|
||||
const fixedSettings = {
|
||||
|
||||
1
src/global.d.ts
vendored
1
src/global.d.ts
vendored
@ -525,6 +525,7 @@ declare global {
|
||||
},
|
||||
rememberVideoSpeed: boolean,
|
||||
extendVideoSpeed: boolean,
|
||||
customKeyBindings: { [actionName: string]: string }
|
||||
}
|
||||
const GM_info: MonkeyInfo
|
||||
function GM_xmlhttpRequest(details: MonkeyXhrDetails): { abort: () => void }
|
||||
|
||||
@ -1,232 +0,0 @@
|
||||
const supportedUrls = [
|
||||
'https://www.bilibili.com/bangumi/',
|
||||
'https://www.bilibili.com/video/',
|
||||
'https://www.bilibili.com/watchlater/',
|
||||
'https://www.bilibili.com/medialist/play/',
|
||||
]
|
||||
let enabled = true;
|
||||
|
||||
(async () => {
|
||||
const { VideoSpeedController } = await import("../video/default-video-speed")
|
||||
|
||||
if (supportedUrls.some(url => document.URL.startsWith(url))) {
|
||||
const clickableKeymap = {
|
||||
f: '.bilibili-player-video-fullscreen', // 全屏
|
||||
w: '.bilibili-player-video-web-fullscreen', // 网页全屏
|
||||
t: '.bilibili-player-video-btn-widescreen', // 宽屏
|
||||
// r: '.bilibili-player-video-btn-repeat', // 切换循环模式
|
||||
m: '.bilibili-player-video-btn-volume .bilibili-player-iconfont-volume', // 切换静音
|
||||
p: '.bilibili-player-video-btn-pip', // 画中画
|
||||
// l: '.video-toolbar .like', // 点赞
|
||||
c: '.video-toolbar .coin,.tool-bar .coin-info, .video-toolbar-module .coin-box, .play-options-ul > li:nth-child(2)', // 投币
|
||||
s: '.video-toolbar .collect, .video-toolbar-module .fav-box, .play-options-ul > li:nth-child(3)', // 收藏
|
||||
' ': '.bilibili-player-video-btn-start', // 砸瓦撸多
|
||||
} as { [key: string]: string }
|
||||
/** 长按`L`三连使用的记忆变量 */
|
||||
let likeClick = true
|
||||
/** 在稍后再看页面里, 记录当前视频是否赞过 */
|
||||
let liked = false
|
||||
const isWatchlater = document.URL.startsWith('https://www.bilibili.com/watchlater/')
|
||||
const isMediaList = document.URL.startsWith('https://www.bilibili.com/medialist/play/')
|
||||
if (isWatchlater) {
|
||||
Observer.videoChange(() => {
|
||||
Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/archive/has/like?aid=${unsafeWindow.aid}`).then(json => {
|
||||
liked = Boolean(json.data)
|
||||
})
|
||||
})
|
||||
}
|
||||
/** 播放速度提示框用的`setTimeout`句柄 */
|
||||
let showPlaybackTipOldTimeout: number
|
||||
/**
|
||||
* 显示播放速度提示框
|
||||
* @param speed 播放速度
|
||||
*/
|
||||
const showPlaybackTip = (speed: number) => {
|
||||
let tip = dq('.keymap-playback-tip') as HTMLDivElement
|
||||
if (!tip) {
|
||||
const player = dq('.bilibili-player-video-wrap')
|
||||
if (!player) {
|
||||
return
|
||||
}
|
||||
player.insertAdjacentHTML('afterbegin', /*html*/`
|
||||
<div class="keymap-playback-tip-container">
|
||||
<i class="mdi mdi-fast-forward"></i>
|
||||
<div class="keymap-playback-tip"></div>x
|
||||
</div>
|
||||
`)
|
||||
resources.applyStyleFromText(`
|
||||
.keymap-playback-tip-container {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 8px 16px;
|
||||
background-color: #000A;
|
||||
color: white;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14pt;
|
||||
border-radius: 4px;
|
||||
transition: .2s ease-out;
|
||||
}
|
||||
.keymap-playback-tip-container.show {
|
||||
opacity: 1;
|
||||
}
|
||||
.keymap-playback-tip-container i {
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
font-size: 18pt;
|
||||
}
|
||||
`, 'keymapStyle')
|
||||
tip = dq('.keymap-playback-tip') as HTMLDivElement
|
||||
}
|
||||
tip.innerHTML = speed.toString()
|
||||
if (showPlaybackTipOldTimeout) {
|
||||
clearTimeout(showPlaybackTipOldTimeout)
|
||||
}
|
||||
(dq('.keymap-playback-tip-container') as HTMLDivElement).classList.add('show')
|
||||
showPlaybackTipOldTimeout = window.setTimeout(() => {
|
||||
(dq('.keymap-playback-tip-container') as HTMLDivElement).classList.remove('show')
|
||||
}, 2000)
|
||||
}
|
||||
document.body.addEventListener('keydown', async e => {
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
if (isWatchlater && document.URL.endsWith('list')) {
|
||||
return
|
||||
}
|
||||
if (document.activeElement && isTyping()) {
|
||||
return
|
||||
}
|
||||
const key = e.key.toLowerCase()
|
||||
const panoramaControl = dq('.bilibili-player-sphere-control') as HTMLElement
|
||||
if (panoramaControl !== null && panoramaControl.style.display !== 'none' && ['w', 'a', 's', 'd'].includes(key)) {
|
||||
return
|
||||
}
|
||||
const noModifyKeys = !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey
|
||||
if (key in clickableKeymap && noModifyKeys) {
|
||||
const element = dq(clickableKeymap[key]) as HTMLElement
|
||||
if (!element) {
|
||||
return
|
||||
}
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
element.click()
|
||||
} else if (key === 'd' && noModifyKeys) { // 切换弹幕开关
|
||||
const checkbox = dq('.bilibili-player-video-danmaku-switch input') as HTMLInputElement
|
||||
if (!checkbox) {
|
||||
return
|
||||
}
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
checkbox.checked = !checkbox.checked
|
||||
raiseEvent(checkbox, 'change')
|
||||
} else if (key === 'j' && noModifyKeys) { // 绯红之王
|
||||
const video = dq('.bilibili-player-video video') as HTMLVideoElement
|
||||
video.currentTime += settings.keymapJumpSeconds
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
} else if (key === 'l' && noModifyKeys) {
|
||||
if (isWatchlater) {
|
||||
const formData = {
|
||||
aid: unsafeWindow.aid,
|
||||
/** `1`点赞; `2`取消赞 */
|
||||
like: liked ? 2 : 1,
|
||||
csrf: getCsrf(),
|
||||
}
|
||||
Ajax.postTextWithCredentials(`https://api.bilibili.com/x/web-interface/archive/like`, Object.entries(formData).map(([k, v]) => `${k}=${v}`).join('&')).then(() => {
|
||||
liked = !liked
|
||||
if (liked) {
|
||||
Toast.success(`已点赞`, `快捷键扩展`, 1000)
|
||||
} else {
|
||||
Toast.success(`已取消点赞`, `快捷键扩展`, 1000)
|
||||
}
|
||||
})
|
||||
} else if (isMediaList) {
|
||||
const likeButton = dq('.play-options-ul > li:first-child') as HTMLLIElement
|
||||
if (likeButton) {
|
||||
likeButton.click()
|
||||
}
|
||||
} else {
|
||||
const likeButton = dq('.video-toolbar .like') as HTMLSpanElement
|
||||
e.preventDefault()
|
||||
const fireEvent = (name: string, args: Event) => {
|
||||
const event = new CustomEvent(name, args)
|
||||
likeButton.dispatchEvent(event)
|
||||
}
|
||||
likeClick = true
|
||||
setTimeout(() => likeClick = false, 200)
|
||||
fireEvent('mousedown', e)
|
||||
document.body.addEventListener('keyup', e => {
|
||||
e.preventDefault()
|
||||
fireEvent('mouseup', e)
|
||||
if (likeClick) {
|
||||
fireEvent('click', e)
|
||||
}
|
||||
}, { once: true })
|
||||
}
|
||||
} else if (key === '`' && noModifyKeys) {
|
||||
// menu size: 386.6 x 311 (2020-03-29)
|
||||
// menu size: 176.65 x 194 (2020-06-09)
|
||||
const player = dq('.bilibili-player-video-wrap') as HTMLElement
|
||||
const rect = player.getBoundingClientRect()
|
||||
player.dispatchEvent(new MouseEvent('contextmenu', {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
view: unsafeWindow,
|
||||
button: 2,
|
||||
buttons: 0,
|
||||
clientX: rect.x + rect.width / 2 - 176.65 / 2,
|
||||
clientY: rect.y + rect.height / 2 - 194 / 2
|
||||
}))
|
||||
} else if (e.shiftKey) {
|
||||
const containerElement = await SpinQuery.select(`.${VideoSpeedController.classNameMap.speedContainer}`) as HTMLElement
|
||||
const videoElement = await SpinQuery.select(`.${VideoSpeedController.classNameMap.video} video`) as HTMLVideoElement
|
||||
|
||||
const controller = new VideoSpeedController(containerElement, videoElement, 1)
|
||||
|
||||
const playbackRates = VideoSpeedController.supportedRates
|
||||
|
||||
let preventDefault = true
|
||||
if (key === '>' || key === 'ArrowUp'.toLowerCase()) { // 天堂制造
|
||||
controller.setVideoSpeed(playbackRates.find(it => it > controller.playbackRate) || playbackRates[playbackRates.length - 1])
|
||||
showPlaybackTip(controller.playbackRate)
|
||||
} else if (key === '<' || key === 'ArrowDown'.toLowerCase()) { // 时间减速
|
||||
controller.setVideoSpeed([...playbackRates].reverse().find(it => it < controller.playbackRate) || playbackRates[0])
|
||||
showPlaybackTip(controller.playbackRate)
|
||||
} else if (key === '?') { // 重置速度
|
||||
controller.reset()
|
||||
showPlaybackTip(controller.playbackRate)
|
||||
} else if (key === 'w') { // 稍后再看
|
||||
const watchlater = dq('.video-toolbar .ops .watchlater, .more-ops-list .ops-watch-later, .video-toolbar-module .see-later-box') as HTMLElement
|
||||
if (watchlater !== null) {
|
||||
watchlater.click()
|
||||
}
|
||||
} else if (key === 'j') { // 败者食尘
|
||||
videoElement.currentTime -= settings.keymapJumpSeconds
|
||||
} else if (key === 's') { // 快速收藏
|
||||
const quickFavorite = dq('.quick-favorite') as HTMLElement
|
||||
if (quickFavorite) {
|
||||
quickFavorite.click()
|
||||
}
|
||||
} else {
|
||||
preventDefault = false
|
||||
}
|
||||
|
||||
if (preventDefault) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})()
|
||||
|
||||
export default {
|
||||
reload: () => enabled = true,
|
||||
unload: () => enabled = false,
|
||||
}
|
||||
72
src/video/keymap/key-bindings.ts
Normal file
72
src/video/keymap/key-bindings.ts
Normal file
@ -0,0 +1,72 @@
|
||||
export type KeyBindingAction = (context: {
|
||||
binding: KeyBinding
|
||||
event: KeyboardEvent
|
||||
isWatchlater: boolean
|
||||
isMediaList: boolean
|
||||
}) => void
|
||||
export interface KeyBinding {
|
||||
keys: string[]
|
||||
action: KeyBindingAction
|
||||
prevent?: boolean
|
||||
}
|
||||
const modifyKeys = [
|
||||
'shift',
|
||||
'alt',
|
||||
'ctrl',
|
||||
'meta',
|
||||
]
|
||||
export const loadKeyBindings = _.once((bindings: KeyBinding[]) => {
|
||||
const isWatchlater = document.URL.startsWith('https://www.bilibili.com/watchlater/')
|
||||
const isMediaList = document.URL.startsWith('https://www.bilibili.com/medialist/play/')
|
||||
const config = {
|
||||
enable: true
|
||||
}
|
||||
document.body.addEventListener('keydown', (e: KeyboardEvent & { [key: string]: boolean }) => {
|
||||
if (!config.enable) {
|
||||
return
|
||||
}
|
||||
// 稍后再看页面无视快捷键
|
||||
if (isWatchlater && document.URL.endsWith('list')) {
|
||||
return
|
||||
}
|
||||
// 打字时无视快捷键
|
||||
if (document.activeElement && isTyping()) {
|
||||
return
|
||||
}
|
||||
const key = e.key.toLowerCase()
|
||||
|
||||
// 全景视频禁用 WASD 无视快捷键
|
||||
const panoramaControl = dq('.bilibili-player-sphere-control') as HTMLElement
|
||||
if (panoramaControl !== null && panoramaControl.style.display !== 'none' && ['w', 'a', 's', 'd'].includes(key)) {
|
||||
return
|
||||
}
|
||||
|
||||
bindings.forEach(binding => {
|
||||
const modifyKeyNotMatch = modifyKeys.some(m => {
|
||||
const needModifyKey = binding.keys.includes(m)
|
||||
const isModifyKeyPressed = e[m + 'Key']
|
||||
return needModifyKey !== isModifyKeyPressed
|
||||
})
|
||||
if (modifyKeyNotMatch) {
|
||||
return
|
||||
}
|
||||
const restKeys = binding.keys.filter(k => !modifyKeys.includes(k.toLowerCase())).map(k => k.toLowerCase())
|
||||
const keyMatch = restKeys.includes(e.key.toLowerCase()) || restKeys.includes(e.code.toLowerCase())
|
||||
if (!keyMatch) {
|
||||
return
|
||||
}
|
||||
|
||||
if (binding?.prevent ?? true) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
}
|
||||
binding.action({
|
||||
binding,
|
||||
isWatchlater,
|
||||
isMediaList,
|
||||
event: e,
|
||||
})
|
||||
})
|
||||
})
|
||||
return config
|
||||
})
|
||||
245
src/video/keymap/keymap.ts
Normal file
245
src/video/keymap/keymap.ts
Normal file
@ -0,0 +1,245 @@
|
||||
import { VideoSpeedController } from '../default-video-speed'
|
||||
import { KeyBinding, KeyBindingAction } from './key-bindings'
|
||||
|
||||
const supportedUrls = [
|
||||
'https://www.bilibili.com/bangumi/',
|
||||
'https://www.bilibili.com/video/',
|
||||
'https://www.bilibili.com/watchlater/',
|
||||
'https://www.bilibili.com/medialist/play/',
|
||||
]
|
||||
|
||||
let config: { enable: boolean }
|
||||
if (supportedUrls.some(url => document.URL.startsWith(url))) {
|
||||
const clickElement = (target: string | HTMLElement) => {
|
||||
return () => {
|
||||
if (typeof target === 'string') {
|
||||
(dq(target) as HTMLElement)?.click()
|
||||
} else {
|
||||
target.click()
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 播放速度提示框用的`setTimeout`句柄 */
|
||||
let showPlaybackTipOldTimeout: number
|
||||
/**
|
||||
* 显示播放速度提示框
|
||||
* @param speed 播放速度
|
||||
*/
|
||||
const showPlaybackTip = (speed: number) => {
|
||||
let tip = dq('.keymap-playback-tip') as HTMLDivElement
|
||||
if (!tip) {
|
||||
const player = dq('.bilibili-player-video-wrap')
|
||||
if (!player) {
|
||||
return
|
||||
}
|
||||
player.insertAdjacentHTML('afterbegin', /*html*/`
|
||||
<div class="keymap-playback-tip-container">
|
||||
<i class="mdi mdi-fast-forward"></i>
|
||||
<div class="keymap-playback-tip"></div>x
|
||||
</div>
|
||||
`)
|
||||
resources.applyStyleFromText(`
|
||||
.keymap-playback-tip-container {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 8px 16px;
|
||||
background-color: #000A;
|
||||
color: white;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14pt;
|
||||
border-radius: 4px;
|
||||
transition: .2s ease-out;
|
||||
}
|
||||
.keymap-playback-tip-container.show {
|
||||
opacity: 1;
|
||||
}
|
||||
.keymap-playback-tip-container i {
|
||||
line-height: 1;
|
||||
margin-right: 8px;
|
||||
font-size: 18pt;
|
||||
}
|
||||
`, 'keymapStyle')
|
||||
tip = dq('.keymap-playback-tip') as HTMLDivElement
|
||||
}
|
||||
tip.innerHTML = speed.toString()
|
||||
if (showPlaybackTipOldTimeout) {
|
||||
clearTimeout(showPlaybackTipOldTimeout)
|
||||
}
|
||||
(dq('.keymap-playback-tip-container') as HTMLDivElement).classList.add('show')
|
||||
showPlaybackTipOldTimeout = window.setTimeout(() => {
|
||||
(dq('.keymap-playback-tip-container') as HTMLDivElement).classList.remove('show')
|
||||
}, 2000)
|
||||
}
|
||||
const videoSpeed = (controllerAction: (controller: VideoSpeedController, rates: number[]) => void) => {
|
||||
return async () => {
|
||||
const attr = await import('../default-video-speed')
|
||||
console.log(attr)
|
||||
const { VideoSpeedController } = await import('../default-video-speed')
|
||||
const containerElement = dq(`.${VideoSpeedController.classNameMap.speedContainer}`) as HTMLElement
|
||||
const videoElement = dq(`.${VideoSpeedController.classNameMap.video} video`) as HTMLVideoElement
|
||||
if (!containerElement || !videoElement) {
|
||||
return
|
||||
}
|
||||
const controller = new VideoSpeedController(containerElement, videoElement, 1)
|
||||
controllerAction(controller, VideoSpeedController.supportedRates)
|
||||
showPlaybackTip(controller.playbackRate)
|
||||
}
|
||||
}
|
||||
const actions = {
|
||||
fullscreen: clickElement('.bilibili-player-video-btn-fullscreen'),
|
||||
webFullscreen: clickElement('.bilibili-player-video-web-fullscreen'),
|
||||
wideScreen: clickElement('.bilibili-player-video-btn-widescreen'),
|
||||
mute: clickElement('.bilibili-player-video-btn-volume .bilibili-player-iconfont-volume'),
|
||||
pictureInPicture: clickElement('.bilibili-player-video-btn-pip'),
|
||||
coin: clickElement('.video-toolbar .coin,.tool-bar .coin-info, .video-toolbar-module .coin-box, .play-options-ul > li:nth-child(2)'),
|
||||
favorite: clickElement('.video-toolbar .collect, .video-toolbar-module .fav-box, .play-options-ul > li:nth-child(3)'),
|
||||
pause: clickElement('.bilibili-player-video-btn-start'),
|
||||
like: (() => {
|
||||
/** 长按`L`三连使用的记忆变量 */
|
||||
let likeClick = true
|
||||
/** 在稍后再看页面里, 记录当前视频是否赞过 */
|
||||
let liked = false
|
||||
|
||||
const listenWatchlaterVideoChange = _.once(() => {
|
||||
Observer.videoChange(() => {
|
||||
Ajax.getJsonWithCredentials(`https://api.bilibili.com/x/web-interface/archive/has/like?aid=${unsafeWindow.aid}`).then(json => {
|
||||
liked = Boolean(json.data)
|
||||
})
|
||||
})
|
||||
})
|
||||
return (({ isWatchlater, isMediaList, event }) => {
|
||||
if (isWatchlater) {
|
||||
listenWatchlaterVideoChange()
|
||||
const formData = {
|
||||
aid: unsafeWindow.aid,
|
||||
/** `1`点赞; `2`取消赞 */
|
||||
like: liked ? 2 : 1,
|
||||
csrf: getCsrf(),
|
||||
}
|
||||
Ajax.postTextWithCredentials(`https://api.bilibili.com/x/web-interface/archive/like`, Object.entries(formData).map(([k, v]) => `${k}=${v}`).join('&')).then(() => {
|
||||
liked = !liked
|
||||
if (liked) {
|
||||
Toast.success(`已点赞`, `快捷键扩展`, 1000)
|
||||
} else {
|
||||
Toast.success(`已取消点赞`, `快捷键扩展`, 1000)
|
||||
}
|
||||
})
|
||||
} else if (isMediaList) {
|
||||
const likeButton = dq('.play-options-ul > li:first-child') as HTMLLIElement
|
||||
if (likeButton) {
|
||||
likeButton.click()
|
||||
}
|
||||
} else {
|
||||
const likeButton = dq('.video-toolbar .like') as HTMLSpanElement
|
||||
event.preventDefault()
|
||||
const fireEvent = (name: string, args: Event) => {
|
||||
const event = new CustomEvent(name, args)
|
||||
likeButton.dispatchEvent(event)
|
||||
}
|
||||
likeClick = true
|
||||
setTimeout(() => likeClick = false, 200)
|
||||
fireEvent('mousedown', event)
|
||||
document.body.addEventListener('keyup', e => {
|
||||
e.preventDefault()
|
||||
fireEvent('mouseup', e)
|
||||
if (likeClick) {
|
||||
fireEvent('click', e)
|
||||
}
|
||||
}, { once: true })
|
||||
}
|
||||
}) as KeyBindingAction
|
||||
})(),
|
||||
danmaku: () => {
|
||||
const checkbox = dq('.bilibili-player-video-danmaku-switch input') as HTMLInputElement
|
||||
if (!checkbox) {
|
||||
return
|
||||
}
|
||||
checkbox.checked = !checkbox.checked
|
||||
raiseEvent(checkbox, 'change')
|
||||
},
|
||||
longJumpBackward: () => {
|
||||
const video = dq('.bilibili-player-video video') as HTMLVideoElement
|
||||
video.currentTime -= settings.keymapJumpSeconds
|
||||
},
|
||||
longJumpForward: () => {
|
||||
const video = dq('.bilibili-player-video video') as HTMLVideoElement
|
||||
video.currentTime += settings.keymapJumpSeconds
|
||||
},
|
||||
playerMenu: () => {
|
||||
// menu size: 386.6 x 311 (2020-03-29)
|
||||
// menu size: 176.65 x 194 (2020-06-09)
|
||||
const player = dq('.bilibili-player-video-wrap') as HTMLElement
|
||||
if (!player) {
|
||||
return
|
||||
}
|
||||
const rect = player.getBoundingClientRect()
|
||||
player.dispatchEvent(new MouseEvent('contextmenu', {
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
view: unsafeWindow,
|
||||
button: 2,
|
||||
buttons: 0,
|
||||
clientX: rect.x + rect.width / 2 - 176.65 / 2,
|
||||
clientY: rect.y + rect.height / 2 - 194 / 2
|
||||
}))
|
||||
},
|
||||
watchlater: clickElement('.video-toolbar .ops .watchlater, .more-ops-list .ops-watch-later, .video-toolbar-module .see-later-box'),
|
||||
quickFavorite: clickElement('.quick-favorite'),
|
||||
videoSpeedIncrease: videoSpeed((controller, rates) => {
|
||||
controller.setVideoSpeed(rates.find(it => it > controller.playbackRate) || rates[rates.length - 1])
|
||||
}),
|
||||
videoSpeedDecrease: videoSpeed((controller, rates) => {
|
||||
controller.setVideoSpeed([...rates].reverse().find(it => it < controller.playbackRate) || rates[0])
|
||||
}),
|
||||
videoSpeedReset: videoSpeed((controller, rates) => {
|
||||
controller.reset()
|
||||
}),
|
||||
}
|
||||
const defaultBindings: { [action in keyof typeof actions]: string } = {
|
||||
fullscreen: 'f',
|
||||
webFullscreen: 'w',
|
||||
wideScreen: 't',
|
||||
mute: 'm',
|
||||
pictureInPicture: 'p',
|
||||
coin: 'c',
|
||||
favorite: 's',
|
||||
pause: 'space',
|
||||
like: 'l',
|
||||
playerMenu: '`',
|
||||
longJumpForward: 'j',
|
||||
longJumpBackward: 'shift j',
|
||||
watchlater: 'shift w',
|
||||
quickFavorite: 'shift s',
|
||||
danmaku: 'd',
|
||||
videoSpeedIncrease: 'shift > ArrowUp',
|
||||
videoSpeedDecrease: 'shift < ArrowDown',
|
||||
videoSpeedReset: 'shift ?',
|
||||
}
|
||||
const parseBindings = (bindings: { [action: string]: string }) => {
|
||||
return Object.entries(bindings).map(([actionName, keyString]) => {
|
||||
const keys = keyString.split(' ')
|
||||
return {
|
||||
keys,
|
||||
action: (actions as any)[actionName] || (() => {}),
|
||||
} as KeyBinding
|
||||
})
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
const { loadKeyBindings } = await import('./key-bindings')
|
||||
config = loadKeyBindings(parseBindings(
|
||||
{ ...defaultBindings, ...settings.customKeyBindings }
|
||||
))
|
||||
})()
|
||||
}
|
||||
|
||||
export default {
|
||||
reload: () => config && (config.enable = true),
|
||||
unload: () => config && (config.enable = false),
|
||||
}
|
||||
@ -1 +1 @@
|
||||
1.11.8
|
||||
1.11.9
|
||||
Loading…
Reference in New Issue
Block a user