Bilibili-Evolved/registry/lib/components/video/player/intersection-actions/index.ts
2023-09-07 21:44:41 +08:00

149 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineComponentMetadata } from '@/components/define'
import { playerAgent } from '@/components/video/player-agent'
import { lightOff, lightOn } from '@/components/video/player-light'
import { videoChange } from '@/core/observer'
import { addComponentListener, getComponentSettings } from '@/core/settings'
import { allVideoUrls } from '@/core/utils/urls'
enum IntersectionMode {
Top = '视频顶部',
Medium = '视频中间',
Bottom = '视频底部',
}
export const component = defineComponentMetadata({
name: 'playerIntersectionActions',
author: {
name: 'Waua',
link: 'https://github.com/FoundTheWOUT',
},
tags: [componentsTags.video],
urlInclude: allVideoUrls,
entry: async ({ settings: { options }, metadata }) => {
const settings = options as {
triggerLocation: IntersectionMode
pause: boolean
light: boolean
}
Promise.resolve().then(async () => {
const {
query: { video },
} = playerAgent
const videoEl = (await video.element()) as HTMLVideoElement
// const playerWrap = await video.wrap()
// 如果有 video-player 优先的使用该盒子
// 因为在稍后再看页面medialist视频也有 player-wrap
// 选择 player-wrap 会导致闪烁。
const playerWrap = (document.getElementById('video-player') ??
(dq('.player-wrap') || dq('.player-module'))) as HTMLElement
let observer: IntersectionObserver
let intersectionLock = true // Lock intersection action
function getToTop(_mode: string): number {
switch (_mode) {
case IntersectionMode.Top:
return 1
case IntersectionMode.Medium:
return 0.5
case IntersectionMode.Bottom:
return 0
default:
return 0.5
}
}
function addPlayerOutEvent() {
// window.addEventListener('scroll', onPlayerOutEvent, { passive: true });
observer.observe(playerWrap)
}
function removePlayerOutEvent() {
// window.removeEventListener('scroll', onPlayerOutEvent);
observer.unobserve(playerWrap)
}
const intersectingCall = () => {
if (intersectionLock) {
return
}
intersectionLock = true // relock
if (settings.pause && videoEl.paused) {
videoEl.play()
}
if (
settings.light &&
getComponentSettings('playerAutoLight').enabled &&
!settings.pause &&
!videoEl.paused
) {
lightOff()
}
}
const disIntersectingCall = () => {
// if video is playing, unlock intersecting action
if (!videoEl.paused) {
intersectionLock = false
}
if (settings.pause && !videoEl.paused) {
videoEl.pause()
}
if (settings.light && getComponentSettings('playerAutoLight').enabled && !settings.pause) {
lightOn()
}
}
const createObserver = (mode?: string) =>
new IntersectionObserver(
([e]) => {
e.isIntersecting ? intersectingCall() : disIntersectingCall()
},
{
threshold: getToTop(mode || settings.triggerLocation),
},
)
function mountPlayListener() {
videoChange(async () => {
if (playerAgent.isAutoPlay()) {
addPlayerOutEvent()
}
videoEl.addEventListener('play', addPlayerOutEvent)
// videoEl.addEventListener('pause', removePlayerOutEvent);
videoEl.addEventListener('ended', removePlayerOutEvent)
})
}
addComponentListener(`${metadata.name}.triggerLocation`, (value: IntersectionMode) => {
removePlayerOutEvent()
observer = createObserver(value)
addPlayerOutEvent()
})
observer = createObserver()
mountPlayListener()
})
},
displayName: '播放器位置动作',
description: {
'zh-CN': '设置当播放器移出视图的位置变化时执行的动作.',
},
options: {
triggerLocation: {
defaultValue: IntersectionMode.Medium,
displayName: '触发位置',
dropdownEnum: IntersectionMode,
},
pause: {
defaultValue: false,
displayName: '自动暂停',
},
light: {
defaultValue: true,
displayName: '自动开灯',
},
},
})