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: '自动开灯', }, }, })