Vimeo,检测全屏以阻止获取新播放器(动态宽度变化) [英] Vimeo, detect fullscreen to block fetching of new player (dynamic width changes)

查看:103
本文介绍了Vimeo,检测全屏以阻止获取新播放器(动态宽度变化)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想根据窗口宽度动态更改vimeo播放器的宽度.您可以在问题的末尾看到该组件的完整代码,也许已经有了一种更简单的方法来动态更改播放器的宽度,因此我根本不必处理这些问题(提供了响应选项通过vimeo不适用于我).

I want to dynamically change the width of my vimeo player adapting to the window width. You can see the full code of the component at the end of the question and maybe there is already a way simpler approach to dynamically change the width of the player so I don't have to deal with the issues at all (The responsive option provided by vimeo does not work for me).

当前解决方案存在的问题:如果播放器进入全屏模式或在全屏模式下旋转手机,我不想触发更改,因为vimeo已经自动处理了这些更改,但是我很难检测是否播放器处于全屏状态.

The issue I am having with my current solution: I don't want to trigger a change if the player goes into fullscreen or rotates the phone on fullscreen since vimeo already handles those changes automatically but I have a hard time to detect if the player is in fullscreen.

    const isFullscreen = (document.fullscreenElement
      || document.webkitFullscreenElement
      || document.mozFullScreenElement
      || document.msFullscreenElement
      || playerWidth === delayedWidth)

此解决方案不适用于iphone 11 pro以及可能所有的Safari浏览器,因为其中没有完全实现fullScreen.

This solution breaks for iphone 11 pro and probably all Safari browsers since fullScreen is not fully implemented there.

import React, {
  useEffect, useContext, useState, useRef,
} from 'react';
import PropTypes from 'prop-types';
import Player from '@vimeo/player';

import STYLES from '../../enums/styles';
import { BrowserContext } from '../../contexts/BrowserContext';

const TAG = 'player';

/**
 * remove event listeners
 * @param {object} playerRef
 */
function removeEventListeners(playerRef) {
  if (!playerRef.current) return;
  playerRef.current.off('ended');
  playerRef.current.off('pause');
  playerRef.current.off('play');
}

/**
 * remove interval
 * @param {object} intervalRef
 */
function removeInterval(intervalRef) {
  if (!intervalRef.current) return;
  window.clearInterval(intervalRef.current);
}

/**
 * 640×480, 800×600, 960×720, 1024×768, 1280×960,
 * 1400×1050, 1440×1080 , 1600×1200, 1856×1392, 1920×1440, and 2048×1536
 * @param {} width
 */
function computeRatio(delayedWidth) {
  const height = window.innerHeight;
  const width = delayedWidth - delayedWidth * 0.1;

  if (height <= 480) {
    return width > 640 ? 640 : width;
  }
  if (height <= 600) {
    return width > 800 ? 800 : width;
  }
  if (height <= 720) {
    return width > 960 ? 960 : width;
  }
  if (height <= 768) {
    return width > 1024 ? 1024 : width;
  }
  if (height <= 960) {
    return width > 1280 ? 1280 : width;
  }
  if (height <= 1050) {
    return width > 1400 ? 1400 : width;
  }
  if (height <= 1080) {
    return width > 1440 ? 1440 : width;
  }
  if (height <= 1200) {
    return width > 1600 ? 1600 : width;
  }
  if (height <= 1392) {
    return width > 1856 ? 1856 : width;
  }
  if (height <= 1440) {
    return width > 1920 ? 1920 : width;
  }
  if (height <= 1536) {
    return width > 2048 ? 2048 : width;
  }
  return width;
}

const VideoPlayer = ({
  index, title, description, link, onProgress, latestProgress,
}) => {
  const { delayedWidth } = useContext(BrowserContext);
  const [time, setTime] = useState(latestProgress < 1 ? latestProgress : 0);
  const playerRef = useRef(null);
  const intervalRef = useRef(null);

  useEffect(() => {
    console.tag(TAG).debug('changing delayed width', delayedWidth);

    const asyncEffect = async () => {
      const player = playerRef.current;
      if (player) {
        const playerWidth = await player.getVideoWidth();
        const isFullscreen = document.fullscreenElement
        || document.webkitFullscreenElement
        || document.mozFullScreenElement
        || document.msFullscreenElement
        || playerWidth === delayedWidth;
        console.tag(TAG).debug('fullscreen detected', isFullscreen);

        const isMobile = window.innerWidth <= STYLES.breakpoints.phoneWidth;
        const isLandscape = window.innerWidth > window.innerHeight;

        if (isFullscreen || (isLandscape && isMobile)) {
          console.tag(TAG).debug('isLandscape, isMobile', isLandscape, isMobile);
          return;
        }

        removeEventListeners(playerRef);
        playerRef.current = null;
        player.pause();
        player.destroy();
      }

      if (intervalRef.current) {
        removeInterval(intervalRef);
        intervalRef.current = null;
      }

      const options = { id: link, width: computeRatio(delayedWidth) };
      const newPlayer = new Player(`frame-${title}-${index}`, options);
      playerRef.current = newPlayer;

      if (time) {
        newPlayer.getDuration().then((duration) => {
          const seconds = duration * time;
          newPlayer.setCurrentTime(seconds);
        });
      }

      const keepTrackProgress = async () => {
        // gets duration of video in seconds
        const duration = await newPlayer.getDuration();

        intervalRef.current = window.setInterval(() => {
          newPlayer.getCurrentTime().then((seconds) => {
            // `seconds` indicates the current playback position of the video
            const progress = seconds / duration;
            console.tag(TAG).debug(`progress: ${progress}, duration ${duration}, seconds ${seconds}`);
            onProgress(progress);
            setTime(progress);
          });
          // track every next 10 seconds of progress
        }, 10000);
      };

      newPlayer.on('ended', () => {
        removeInterval(intervalRef);
        intervalRef.current = null;
        onProgress(1);
        setTime(1);
      });

      newPlayer.on('pause', ({ duration, seconds }) => {
        removeInterval(intervalRef);
        intervalRef.current = null;
        const progress = seconds / duration;
        console.tag(TAG).debug(`progress at paused: ${progress}, duration ${duration}, seconds ${seconds}`);
        onProgress(progress);
        setTime(progress);
      });

      newPlayer.on('play', () => {
        keepTrackProgress();
      });
    };

    asyncEffect();
    return () => {
      removeInterval(intervalRef);
      removeEventListeners(playerRef);
    };
  }, [delayedWidth]);

  return (
    <div className="video-player">
      <div id={`frame-${title}-${index}`} className="frame-wrapper" />
      <div className="details">
        <h1>{title}</h1>
        <p>{description}</p>
      </div>
    </div>
  );
};


VideoPlayer.propTypes = {
  index: PropTypes.number.isRequired,
  title: PropTypes.string.isRequired,
  description: PropTypes.string.isRequired,
  link: PropTypes.string.isRequired,
  onProgress: PropTypes.func.isRequired,
  latestProgress: PropTypes.number.isRequired,
};

export default VideoPlayer;

推荐答案

@ vimeo/player软件包背后的团队发布了新的全屏方法!它就像一种魅力,可以解决我的问题.

The team behind the @vimeo/player package released new fullscreen methods! It works like a charm and solves my issue.

如果遇到类似问题,请查看更新的@ vimeo/player文档:

If you are running into similar issues, have a look at the updated @vimeo/player documentation: https://www.npmjs.com/package/@vimeo/player#getfullscreen-promiseboolean-error

我经过更新和测试的代码如下:

My updated and tested code looks like this:

import React, {
  useEffect, useContext, useState, useRef,
} from 'react';
import PropTypes from 'prop-types';
import Player from '@vimeo/player';

import { BrowserContext } from '../../contexts/BrowserContext';

const TAG = 'player';

/**
 * remove event listeners
 * @param {object} player
 */
function removeEventListeners(player) {
  if (!player) return;
  player.off('ended');
  player.off('pause');
  player.off('play');
}
/**
 * remove interval
 * @param {number} interval
 */
function removeInterval(interval) {
  console.tag(TAG).debug('removeInterval called');
  window.clearInterval(interval);
}

/**
 * 640×480, 800×600, 960×720, 1024×768, 1280×960,
 * 1400×1050, 1440×1080 , 1600×1200, 1856×1392, 1920×1440, and 2048×1536
 * @param {number} width
 */
function computeRatio(delayedWidth, percentage = 0.9) {
  const height = window.innerHeight;
  const width = delayedWidth - (delayedWidth * (1 - percentage));

  if (height <= 480) {
    return width > 640 ? 640 : width;
  }
  if (height <= 600) {
    return width > 800 ? 800 : width;
  }
  if (height <= 720) {
    return width > 960 ? 960 : width;
  }
  if (height <= 768) {
    return width > 1024 ? 1024 : width;
  }
  if (height <= 960) {
    return width > 1280 ? 1280 : width;
  }
  if (height <= 1050) {
    return width > 1400 ? 1400 : width;
  }
  if (height <= 1080) {
    return width > 1440 ? 1440 : width;
  }
  if (height <= 1200) {
    return width > 1600 ? 1600 : width;
  }
  if (height <= 1392) {
    return width > 1856 ? 1856 : width;
  }
  if (height <= 1440) {
    return width > 1920 ? 1920 : width;
  }
  if (height <= 1536) {
    return width > 2048 ? 2048 : width;
  }
  return width;
}

const VideoPlayer = ({
  index, link, onProgress, latestProgress, widthPercentage, onVideoEnded,
}) => {
  const { delayedWidth } = useContext(BrowserContext);
  const [progress, setProgress] = useState(latestProgress < 1 ? latestProgress : 0);
  const playerRef = useRef(null);
  const intervalRef = useRef(null);

  useEffect(() => {
    console.tag(TAG).debug('changing delayed width', delayedWidth);

    const asyncEffect = async () => {
      const player = playerRef.current;
      if (player) {
        console.tag(TAG).debug('player detected, checking fullscreen');
        const isFullscreen = await player.getFullscreen();
        console.tag(TAG).debug('fullscreen detected', isFullscreen);

        if (isFullscreen) {
          return;
        }

        removeEventListeners(player);
        playerRef.current = null;
        player.pause(); // gets rid of interval
        player.destroy();
      }

      const options = { id: link, width: computeRatio(delayedWidth, widthPercentage) };
      const newPlayer = new Player(`frame-${index}`, options);
      playerRef.current = newPlayer;

      if (progress) {
        newPlayer.getDuration().then((duration) => {
          const seconds = duration * progress;
          newPlayer.setCurrentTime(seconds);
        });
      }

      const keepTrackProgress = async () => {
        // gets duration of video in seconds
        const duration = await newPlayer.getDuration();

        intervalRef.current = window.setInterval(() => {
          const currentPlayer = playerRef.current;
          if (!currentPlayer) {
            return;
          }
          currentPlayer.getCurrentTime().then((seconds) => {
            // `seconds` indicates the current playback position of the video
            const newProgress = seconds / duration;
            console.tag(TAG).debug(`progress: ${newProgress}, duration ${duration}, seconds ${seconds}`);
            onProgress(newProgress);
            setProgress(newProgress);
          });
          // track every next 10 seconds of progress
        }, 10000);
      };

      newPlayer.on('ended', () => {
        console.tag(TAG).debug('player onEnded');
        removeInterval(intervalRef.current);
        intervalRef.current = null;
        onProgress(1);
        setProgress(1);
        onVideoEnded();
      });

      newPlayer.on('pause', ({ duration, seconds }) => {
        console.tag(TAG).debug('player onPause');
        removeInterval(intervalRef.current);
        intervalRef.current = null;
        const newProgress = seconds / duration;
        console.tag(TAG).debug(`progress at paused: ${newProgress}, duration ${duration}, seconds ${seconds}`);
        onProgress(newProgress);
        setProgress(newProgress);
      });

      newPlayer.on('play', () => {
        console.tag(TAG).debug('player onPlay');
        keepTrackProgress();
      });
    };

    asyncEffect();
  }, [delayedWidth]);

  useEffect(() => () => {
    removeInterval(intervalRef.current);
    removeEventListeners(playerRef.current);
    if (playerRef.current) {
      playerRef.current.destroy();
    }
  }, []);

  return (
    <div id={`frame-${index}`} className="frame-wrapper" />
  );
};


VideoPlayer.propTypes = {
  index: PropTypes.number.isRequired,
  link: PropTypes.string.isRequired,
  onProgress: PropTypes.func.isRequired,
  onVideoEnded: PropTypes.func,
  latestProgress: PropTypes.number.isRequired,
  widthPercentage: PropTypes.number,
};

VideoPlayer.defaultProps = {
  widthPercentage: 0.9,
  onVideoEnded: () => {},
};

export default VideoPlayer;

这篇关于Vimeo,检测全屏以阻止获取新播放器(动态宽度变化)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆