Merge pull request #1785 from FoundTheWOUT/feat

自动暂停与自动关灯
This commit is contained in:
Grant Howard 2021-04-28 14:45:34 +08:00 committed by GitHub
commit a12dfdeb68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 176 additions and 0 deletions

View File

@ -678,5 +678,18 @@ Resource.manifest = {
},
},
autoPlayControl: '传统连播模式',
scrollOutPlayer: {
displayNames: {
scrollOutPlayer: '当播放器退出页面时',
scrollOutPlayerTriggerPlace: '选定触发位置',
scrollOutPlayerAutoPause: '自动暂停',
scrollOutPlayerAutoLightOn: '自动开灯'
},
reloadable: true,
dropdown:{
key: 'scrollOutPlayerTriggerPlace',
items: ['视频顶部' ,'视频中间', '视频底部']
}
}
}
export const resourceManifest = Resource.manifest

View File

@ -256,6 +256,10 @@ export const settings = {
fullscreenGiftBox: false,
autoPlayControl: true,
cache: {},
scrollOutPlayer: true,
scrollOutPlayerTriggerPlace: '视频中间',
scrollOutPlayerAutoPause: true,
scrollOutPlayerAutoLightOn: true,
}
const fixedSettings = {
seedsToCoins: false,

4
src/global.d.ts vendored
View File

@ -518,6 +518,10 @@ declare global {
liveSpeedBoost: boolean,
checkInCenter: boolean,
fullscreenGiftBox: boolean,
scrollOutPlayer: boolean,
scrollOutPlayerTriggerPlace: string[],
scrollOutPlayerAutoPause: boolean,
scrollOutPlayerAutoLightOn: boolean,
}
const GM_info: MonkeyInfo
function GM_xmlhttpRequest(details: MonkeyXhrDetails): { abort: () => void }

View File

@ -75,6 +75,10 @@
<checkbox indent="0" key="removeVideoPopup" dependencies=""></checkbox>
<checkbox indent="0" key="removeVotePopup" dependencies=""></checkbox>
<checkbox indent="0" key="autoPlayControl" dependencies=""></checkbox>
<checkbox indent="0" key="scrollOutPlayer" dependencies=""></checkbox>
<dropdown indent="1" key="scrollOutPlayerTriggerPlace" dependencies="scrollOutPlayer"></dropdown>
<checkbox indent="1" key="scrollOutPlayerAutoPause" dependencies="scrollOutPlayer"></checkbox>
<checkbox indent="1" key="scrollOutPlayerAutoLightOn" dependencies="scrollOutPlayer"></checkbox>
<category icon="style">样式</category>
<li class="indent-0 folded">
<label class="gui-settings-textbox-container">

View File

@ -239,6 +239,10 @@ export const toolTips = new Map<keyof BilibiliEvolvedSettings, string>([
[`fullscreenGiftBox`, /*html*/`在网页全屏状态下, 可以直接点开礼物包裹, 方便送辣条和小心心.`],
[`keymapPreset`, /*html*/`更换快捷键的预设.`],
[`autoPlayControl`, /*html*/`使用传统的连播模式, 视频有多P时 / 在收藏夹或稍后再看列表里时自动开启连播, 单P视频自动关闭连播防止播放推荐视频.`],
[`scrollOutPlayer`, /*html*/`播放器被移出页面时触发动作.`],
[`scrollOutPlayerAutoPause`, /*html*/`播放器的<span>选定触发位置</span>被移出页面时自动暂停播放, 且当播放器回来时恢复播放.`],
[`scrollOutPlayerAutoLightOn`, /*html*/`在没有开启自动暂停, 且开启了播放时自动关灯, 那么该功能会在播放器的<span>选定触发位置</span>被移出页面时自动开灯, 当播放器回来时自动关灯.
<b>: 在自动暂停开启时, </b>`]
]);
export default {
export: { toolTips },

View File

@ -0,0 +1,147 @@
let videoEl: HTMLVideoElement;
let mode = '视频中间';
enum MODE {
TOP = '视频顶部',
MID = '视频中间',
BOT = '视频底部',
}
function getToTop(_mode: string, client: DOMRect): number {
switch (_mode) {
case MODE.TOP:
return client?.top;
case MODE.MID:
return client?.top + client?.height / 2;
case MODE.BOT:
return client?.top + client?.height;
default:
return 0;
}
}
// run callback when video el scroll out.
let handlePlayerOut = function (_mode: string, callback?: () => void) {
const videoClient = videoEl?.getBoundingClientRect();
if (videoClient?.top && videoClient.height) {
let toTop = getToTop(_mode, videoClient);
if (toTop <= 0) {
callback ? callback() : '';
// get ready to check when the video el came back.
window.addEventListener('scroll', onPlayerBackEvent, {
passive: true,
});
// remove out listener when got out.
window.removeEventListener('scroll', onPlayerOutEvent);
}
}
};
// run callback when video el scroll back.
let handlePlayerBack = function (_mode: string, callback?: () => void) {
const videoClient = videoEl?.getBoundingClientRect();
if (videoClient?.top && videoClient.height) {
let toTop = getToTop(_mode, videoClient);
if (toTop >= 0) {
callback ? callback() : '';
// this will done by play listener
window.addEventListener('scroll', onPlayerOutEvent, {
passive: true,
});
window.removeEventListener('scroll', onPlayerBackEvent);
}
}
};
let lightOff = () => {};
let lightOn = () => {};
async function initLights() {
await SpinQuery.unsafeJquery();
const settingsButton = await SpinQuery.any(() =>
unsafeWindow.$('.bilibili-player-video-btn-setting')
);
if (!settingsButton) {
return;
}
settingsButton.mouseover().mouseout();
const setLight = async (state: boolean) => {
const checkbox = (await SpinQuery.select(
'.bilibili-player-video-btn-setting-right-others-content-lightoff .bui-checkbox-input'
)) as HTMLInputElement;
checkbox.checked = state;
raiseEvent(checkbox, 'change');
};
lightOff = () => setLight(true);
lightOn = () => setLight(false);
}
function onPlayerOutEvent() {
handlePlayerOut(mode, () => {
if (settings.scrollOutPlayerAutoPause && !videoEl.paused) videoEl.pause();
// 满足条件: 自动开灯功能启用、自动关灯功能启用、没有启用自动暂停
// 补充: 当启用自动关灯与自动暂停时, 自动开灯动作由自动暂停完成
if (
settings.scrollOutPlayerAutoLightOn &&
settings.autoLightOff &&
!settings.scrollOutPlayerAutoPause
)
lightOn();
});
}
function onPlayerBackEvent() {
handlePlayerBack(mode, () => {
if (settings.scrollOutPlayerAutoPause && videoEl.paused) videoEl.play();
// 回来时自动关灯
// 满足条件: 自动开灯功能启用、自动关灯功能启用、没有启用自动暂停、视频播放中
if (
settings.scrollOutPlayerAutoLightOn &&
settings.autoLightOff &&
!settings.scrollOutPlayerAutoPause &&
!videoEl.paused
)
lightOff();
});
}
function addPlayerOutEvent() {
window.addEventListener('scroll', onPlayerOutEvent, { passive: true });
}
function removePlayerOutEvent() {
window.removeEventListener('scroll', onPlayerOutEvent);
}
function mountListener() {
Observer.videoChange(async () => {
videoEl.addEventListener('play', addPlayerOutEvent);
// onPlayerOutEvent 不会在我们手动暂停视频时移除, 所以需要监听暂停.
videoEl.addEventListener('pause', removePlayerOutEvent);
videoEl.addEventListener('ended', removePlayerOutEvent);
});
}
async function setup() {
await initLights();
addSettingsListener('triggerPlayerOutPlace', (value) => (mode = value));
videoEl = dq('.bilibili-player-video video') as HTMLVideoElement;
mountListener();
}
setup();
export default {
reload: () => {
window.addEventListener('scroll', onPlayerOutEvent);
mountListener();
},
unload: () => {
// remove all listener
Observer.videoChange(async () => {
videoEl.removeEventListener('play', addPlayerOutEvent);
videoEl.removeEventListener('pause', removePlayerOutEvent);
videoEl.removeEventListener('ended', removePlayerOutEvent);
});
window.removeEventListener('scroll', onPlayerOutEvent);
window.removeEventListener('scroll', onPlayerBackEvent);
},
};