当观看者切换浏览器选项卡或最小化浏览器时播放/暂停 Vimeo 视频 window

Play / pause Vimeo Video when watcher switches browser tab or minimize browser window

我正在使用 Vimeo Pro 在 Wordpress 网站上上传视频课程,然后,我使用 H5P 向视频添加交互。

为了在 H5P 互动视频中插入这些 vimeo 视频,我需要使用 Vimeo Pro 的 .mp4 分发版(而不是 Vimeo Iframe)。这是一个例子:

https://player.vimeo.com/external/376040732.sd.mp4?s=a88abddb83ad31962643b6c4dd8270323d80874e&profile_id=165


在网站上

如果我检查我的网站,这是代码:

<div class="h5p-video-wrapper h5p-video hardware-accelerated">

<video src="https://player.vimeo.com/external/376040732.sd.mp4?s=a88abddb83ad31962643b6c4dd8270323d80874e&amp;profile_id=165" webkit-playsinline="" playsinline="" preload="metadata" disableremoteplayback="" class="h5p-video" style="display: block;">
</video>
<div class="h5p-overlay h5p-ie-transparent-background"></div>

</div>

我的请求

学生切换浏览器选项卡或最小化浏览器时暂停视频的最简单方法是什么window?感谢您的帮助!

编辑 - 解决方案

如果您在网页中插入 仅一个 H5P 互动视频,那么 Matt Oestreich 和 Oliver Tacke 的脚本都有效。

注意:如果您需要在网页中插入多个 H5P 互动视频,请使用 Matt Oestreich 的脚本。



答案:

由于这些答案中的字符限制,我不得不清除很多以前的更新。

我设法让它与多个 iframe 一起工作..

唯一的问题是如果有人播放 2 个不同的视频,然后点击不同的选项卡(暂停所有视频)然后他们回来,它将播放所有视频...我可以试试想办法解决这个问题,但现在应该可以了。

确保同时查看上面更新的演示站点..

只需将此脚本放在任何包含您希望 pause/play 使用页面可见 API 的视频的页面上,其余的应该自行处理。

您将需要使用以下内容:

const THE_IFRAME_SELECTOR = 'iframe[id^="h5p-iframe-"]'; // matches all iframes with an id that starts with h5p-iframe-
const THE_VIDEO_SELECTOR = 'video.h5p-video'; // since all videos appear to have the same class you don't need to change this

因此,新的脚本应该是这样的:

// ====================================================================================================================
// ~~~ SECOND SCRIPT ~~~ 
// THIS WAITS FOR THE IFRAME AND THE VIDEO INSIDE OF THE IFRAME TO BE CREATED BEFORE INITIALIZING THE PAGE VISIBLE API
// ====================================================================================================================
// "Global" variables.
const THE_IFRAME_SELECTOR = 'iframe[id^="h5p-iframe-"]'; // matches all iframes with an id that starts with h5p-iframe-
const THE_VIDEO_SELECTOR = 'video.h5p-video'; // since all videos appear to have the same class you don't need to change this

waitForMultipleElements(document, THE_IFRAME_SELECTOR, () => {
  let ALL_IFRAMES = document.querySelectorAll(THE_IFRAME_SELECTOR);
  ALL_IFRAMES.forEach(FOUND_IFRAME => {
    let FOUND_IFRAME_SELECTOR = `#${FOUND_IFRAME.id}`;
    console.log("FOUND_IFRAME_SELECTOR:", FOUND_IFRAME_SELECTOR)
    waitForElement(document, FOUND_IFRAME_SELECTOR, () => {
      waitForVideoElement(FOUND_IFRAME_SELECTOR, THE_VIDEO_SELECTOR, () => {
        initPageVisibleApi(FOUND_IFRAME_SELECTOR, THE_VIDEO_SELECTOR);
      });
    });
  });
});

function waitForMultipleElements(parentEl, selector, callback) {
  let theInterval = setInterval(() => {
    console.log('still waiting for all elements: ' + selector);
    let elements = parentEl.querySelectorAll(selector);
    if (elements.length) {
      console.log("elements: " + selector + " exist!");
      clearInterval(theInterval);
      callback();
    }
  }, 1000);
}

function waitForVideoElement(iframeSelector, videoElementSelector, callback) {
  let theIframeElement = document.querySelector(iframeSelector);
  let iframeEl = theIframeElement.contentWindow.document;
  waitForElement(iframeEl, videoElementSelector, () => {
    callback()
  });
}

function waitForElement(parentEl, selectorOfElementToWaitFor, callback) {
  let theInterval = setInterval(() => {
    console.log("still waiting for " + selectorOfElementToWaitFor);
    let element = parentEl.querySelector(selectorOfElementToWaitFor);
    if (element) {
      console.log(selectorOfElementToWaitFor + " exists!");
      clearInterval(theInterval);
      callback();
    }
  }, 100);
}

function initPageVisibleApi(iframeSelector, videoSelector) {
  // This is the same code that builds out the Page Visible API
  // event listeners. 
  // The only difference is I wrapped it in a function and added 
  // parameters to make it flexible.
  const iframe = document.querySelector(iframeSelector);
  const innerDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
  const videoElement = innerDoc.querySelector(videoSelector);
  // Set the name of the hidden property and the change event for visibility
  var hidden, visibilityChange;
  if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
    hidden = "hidden";
    visibilityChange = "visibilitychange";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden";
    visibilityChange = "msvisibilitychange";
  } else if (typeof document.webkitHidden !== "undefined") {
    hidden = "webkitHidden";
    visibilityChange = "webkitvisibilitychange";
  }

  // To tell if video has been played yet or not
  let VIDEO_HAS_BEEN_PLAYED = false;
  // If the page is hidden, pause the video;
  // if the page is shown, play the video
  function handleVisibilityChange() {
    if (VIDEO_HAS_BEEN_PLAYED) {
      if (document[hidden]) {
        videoElement.pause();
      } else {
        videoElement.play();
      }
    }
  }
  // Warn if the browser doesn't support addEventListener or the Page Visibility API
  if (typeof document.addEventListener === "undefined" || hidden === undefined) {
    alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
  } else {
    // Handle page visibility change   
    document.addEventListener(visibilityChange, handleVisibilityChange, false);

    // When the video pauses, set the title.
    // This shows the paused
    const defaultTitle = document.title;
    videoElement.addEventListener("pause", function () {
      document.title = 'Paused - ' + defaultTitle;
    }, false);
    // When the video plays, set the title.
    videoElement.addEventListener("play", function () {
      VIDEO_HAS_BEEN_PLAYED = true;
      document.title = 'Playing - ' + defaultTitle;
    }, false);
  }
}
// ====================================================================================================================
// ---------- END SECOND SCRIPT ------------
// ====================================================================================================================

如果你想修改 H5P 的功能超出 "hack",你可能应该使用自定义它的常用方法。它通常会使事情变得容易得多。详情请见https://h5p.org/wordpress-customization

无论如何,如果您想在 WordPress 主题中添加一些脚本,应该这样做:

// This will only work for the first H5P IV found on the page!
// Since I don't know your environment, let's stick with ES5
var hidden, visibilityChange;
var interactiveVideo;
var currentState = -1;
var restartVideo = false;

/**
 * Handle change of page visibility.
 */
function handleVisibilityChange() {
  if ( ! interactiveVideo ) {
    return;
  }

  if ( document[hidden] ) {
    // There's nothing to do if the video isn't playing at all
    if ( 1 !== currentState ) {
      return;
    }

    restartVideo = true;
    interactiveVideo.pause();
  }
  else {
    // Restart if video was playing before
    if ( ! restartVideo ) {
      return;
    }

    restartVideo = false;
    interactiveVideo.play();
  }
}

/**
 * Add the stop/resume feature to video.
 * @param {Window} contentWindow Content Window containing H5P.
 */
function addVideoStopResume( contentWindow ) {
  // Set the name of the hidden property and the change event for visibility
  if ( 'undefined' !== typeof document.hidden ) { // Opera 12.10 and Firefox 18 and later support
    hidden = 'hidden';
    visibilityChange = 'visibilitychange';
  }
  else if ( 'undefined' !== typeof document.msHidden ) {
    hidden = 'msHidden';
    visibilityChange = "msvisibilitychange";
  }
  else if ( 'undefined' !== typeof document.webkitHidden ) {
    hidden = 'webkitHidden';
    visibilityChange = 'webkitvisibilitychange';
  }

  // Get first instance of H5P.interactiveVideo -- will not work properly if there are more instances of IV!
  interactiveVideo = interactiveVideo || contentWindow.H5P.instances.filter( function ( instance ) {
    return instance.libraryInfo && 'H5P.InteractiveVideo' === instance.libraryInfo.machineName;
  })[0];

  if ( ! interactiveVideo ) {
    return;
  }

  // Remember current video state
  interactiveVideo.video.on('stateChange', function (state) {
    currentState = state.data;
  });

  if ( 'undefined' === typeof document.addEventListener || undefined === hidden ) {
    console.warn( 'The video stop/resume feature requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.' );
  }
  else {
    // Handle page visibility change
    document.addEventListener( visibilityChange, handleVisibilityChange, false );
  }
}

/**
 * Initialize stop/resume feature.
 */
function initVideoStopResume() {
  var iframes = document.getElementsByTagName( 'iframe' );
  var i;
  var contentWindow;

  // Add EventListener if H5P content is present
  if ( 'complete' === document.readyState ) {
    for ( i = 0; i < iframes.length; i++ ) {

      // Skip non H5P iframes and remote iframes
      if ( ! iframes[i].classList.contains( 'h5p-iframe' ) &&
        (
          0 !== iframes[i].src.indexOf( window.location.origin ) ||
                    -1 === iframes[i].src.indexOf( 'action=h5p_embed' )
        )
      ) {
        continue;
      }

      // Edge needs to wait for iframe to be loaded, others don't
      contentWindow = iframes[i].contentWindow;
      if ( contentWindow.H5P ) {
        addVideoStopResume( contentWindow );
      }
      else {
        iframes[i].addEventListener( 'load', function () {
          contentWindow = this.contentWindow;
          addVideoStopResume( contentWindow );
        });
      }
    }
  }
}

// Amend content functionality when H5P content has loaded
if ( 'complete' === document.readyState ) {
  initVideoStopResume();
}
else {
  document.onreadystatechange = function () {
    if ( 'complete' === document.readyState ) {
      initVideoStopResume();
    }
  };
}

脚本将等到页面加载完毕,然后遍历页面上的每个 H5P iframe 以搜索互动视频。然后它将所需的功能添加到 stop/resume 一个关于可见性更改的视频。

请注意,如果您在其他内容类型(如 H5P 列)中使用 IV,此解决方案将无法正常工作。此外,它仅适用于页面上的第一个交互式视频。添加这些功能需要更多代码,因此未被要求。