播放 Soundcloud embed 时暂停 Youtube embed

我有一个音乐博客,其中包含各种嵌入式 soundcloud 和 youtube 播放器.

I have a music blog that contains various embedded soundcloud and youtube players.

我想要做的是防止任何音频同时播放.换句话说,当我播放 youtube 视频时,如果我点击播放 soundcloud embed,我希望 youtube 播放器暂停,反之亦然.

What I want to do is prevent any audio from playing simultaneously. In other words while I am playing a youtube video, if I click to play the soundcloud embed I want the youtube player to pause and vice versa.

如果我点击播放另一个 youtube 播放器,我已经开发了暂停流式 youtube 播放器的代码(soundcloud 已经固有地这样做了).我只需要使它交叉兼容.真的很感激一些帮助,谢谢.

I have developed code that pauses the streaming youtube player if I click to play another youtube player (soundcloud already does this inherently). I just need to make it cross compatible. Really would appreciate some help, thanks.

var playerCurrentlyPlaying = null;
var players = {}
YT_ready(function() {
   $(".youtube_embed").each(function() {
       var identifier = this.id;
       var frameID = getFrameID(identifier);
       if (frameID) {
            players[frameID] = new YT.Player(frameID, {
                events: {
                    "onStateChange": function(event){
                        if (event.data == YT.PlayerState.PLAYING)
                        {
                            if(playerCurrentlyPlaying != null &&
                               playerCurrentlyPlaying != frameID)
                            callPlayer( playerCurrentlyPlaying , 'pauseVideo' );
                            playerCurrentlyPlaying = frameID;
                        }
                    }
                }
            });
        }
   });
});

我使用了以下来源的函数:在 JavaScript 或 jQuery 中监听 Youtube 事件

I have used functions from these sources: Listening for Youtube Event in JavaScript or jQuery

YouTube iframe API:如何控制 HTML 中已有的 iframe 播放器?

YouTube API 目标(多个)现有 iframe

使用 UniqueID() 渲染 HTML:

Rendered HTML using UniqueID():

<span class="soundcloud_embed" id="soundcloud_post_312">
  <iframe id="ui-id-1" width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F103518792&show_artwork=true&secret_token=s-LnOTK"></iframe>
</span>

<span class="youtube_embed" id="youtube_post_309">
  <iframe id="ui-id-2" width="528" height="190" src="//www.youtube.com/embed/Y3CYKXBEtf0" frameborder="0" allowfullscreen></iframe>
</span>

推荐答案

首先,如果您能够在 iframe 上自己获取 ID,事情将大大简化,如下所示:

First of all, things will be greatly simplified if you are able to get an ID onto the iframes themselves, like this:

<span class="soundcloud_embed">
  <iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F4997623" id="sound1"></iframe>
</span>
<span class="soundcloud_embed">
  <iframe width="100%" height="166" scrolling="no" frameborder="no" src="https://w.soundcloud.com/player/url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F105153133" id="sound2"></iframe>
</span>
<span class="youtube_embed">
  <iframe width="400" height="225" src="//www.youtube.com/embed/tv8WgLEIPBg" id="vid1" frameborder="0" allowfullscreen></iframe>
</span>
<span class="youtube_embed">
  <iframe width="400" height="225" src="//www.youtube.com/embed/FmICU1gMAAw" id="vid2" frameborder="0" allowfullscreen></iframe>
</span>

如果您不想破解您提到的 auto_html gem 来获取 ID,您可以使用 jquery 的 .uniqueId() 函数在所有 iframe 上生成它们或使用 getFrameID() 您提到的帖子中的辅助方法(并且似乎已经在使用).

If you'd prefer not to hack the auto_html gem that you mention in order to get IDs, you can either use jquery's .uniqueId() function to generate them on all iframes or use the getFrameID() helper method from the post you referred to (and seem to already be using).

为了尽可能轻松地让两个 API(Youtube 和 Soundcloud)能够响应彼此的事件,您可以使用几个控制对象来跟踪哪些玩家在您的页面上以及哪些其中正在播放(此策略类似于您提到的链接所采用的策略,但已扩展为能够跟踪哪个播放器属于哪个 API).使用它,定义一个通用的暂停函数,作为两个 API 的简单包装器:

To make it as easy as possible to get the two APIs (Youtube and Soundcloud) to be able to respond to each other's events, you can use a couple of control objects that keep track of which players are on your page and which of them is currently playing (this strategy is similar to that employed by the links you referred to, but are expanded to be able to keep track of which player belongs to which API). With it, define a generic pause function that serves as a simplistic wrapper for both APIs:

var playerCurrentlyPlaying = {"api":null,"frameID":null};
var players = {"yt":{},"sc":{}};

pauseCurrentPlayer=function() {
  var api=playerCurrentlyPlaying["api"],
      frameid=playerCurrentlyPlaying["frameID"];

  switch(api) {
    case "yt":
      players[api][frameid].pauseVideo();
      break;
    case "sc":
      players[api][frameid]["widget"].pause();
      break;
  }
};

接下来,您需要定义两个单独的函数;第一个将在捕获 YouTube 播放事件时调用,第二个将在捕获 Soundcloud 播放事件时调用.目前,Soundcloud HTML5 Widget 有一些错误,迫使必须包含一些非常丑陋的 hack——即,当您第一次播放 Soundcloud 声音时,有时不会触发 Play 事件.幸运的是,Play_Progress 事件是,所以我们可以利用它,但还必须包含一个解决方法,这样它就不会在暂停声音和开始视频时产生竞争条件:

Next, you'll want to define two separate functions; the first will be called whenever a YouTube play event is captured, and the second whenever a Soundcloud play event is captured. Currently the Soundcloud HTML5 Widget has a few bugs that force the necessity to include some pretty ugly hacks--namely, the Play event sometimes isn't fired when you play a Soundcloud sound for the first time. Luckily, the Play_Progress event is, so we can leverage that, but must also include a workaround so it doesn't create a race condition when pausing a sound and starting a video:

onYTPlay =function(frameid) {
  if (playerCurrentlyPlaying["frameID"]!=frameid && playerCurrentlyPlaying["frameID"]!=null) {
     pauseCurrentPlayer();
  }
  playerCurrentlyPlaying["api"]="yt";
  playerCurrentlyPlaying["frameID"]=frameid;
};

onSCPlay=function(frameid,event) {
  if (event==SC.Widget.Events.PLAY||players["sc"][frameid]["firstplay"]==true) {
     if (playerCurrentlyPlaying["api"]=="yt") { // because any soundcloud player will be automatically paused by another soundcloud event, we only have to worry if the currently active player is Youtube
        pauseCurrentPlayer();
     }
     playerCurrentlyPlaying["api"]="sc";
     playerCurrentlyPlaying["frameID"]=frameid;
     players["sc"][frameid]["firstplay"]=false;
  }
};

最后,您可以将挂钩添加到 Youtube 嵌入和 Soundcloud 嵌入中,记住我们必须为 Soundcloud Play 事件添加的技巧.不要忘记嵌入 Soundcloud Widget API (<script src="w.soundcloud.com/player/api.js"; type="text/javascript"></script>),然后使用此代码进行绑定:

Finally, you can then add your hooks to the Youtube embeds and the Soundcloud embeds, remembering the hack we have to put in for the Soundcloud Play event. Don't forget to embed the Soundcloud Widget API (<script src="w.soundcloud.com/player/api.js"; type="text/javascript"></script>), and then use this code to do your bindings:

var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

function onYouTubeIframeAPIReady() {
  $(".youtube_embed iframe").each(function() {
    players["yt"][$(this).attr('id')] = new YT.Player($(this).attr('id'), {
      events: { 'onStateChange': onYTPlayerStateChange }
    });
  });
}

onYTPlayerStateChange = function(event) {
  if (event.data==YT.PlayerState.PLAYING) {
     onYTPlay(event.target.a.id);
  }
};

(function(){
    $(".soundcloud_embed iframe").each(function() {
      var frameid=$(this).attr('id');
      players["sc"][frameid]={};
      players["sc"][frameid]={"widget":SC.Widget(document.getElementById(frameid)),"firstplay":true};
      players["sc"][frameid]["widget"].bind(SC.Widget.Events.READY, function() {
       players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY, function() {
        onSCPlay(frameid,SC.Widget.Events.PLAY);
       });
       players["sc"][frameid]["widget"].bind(SC.Widget.Events.PLAY_PROGRESS, function() {
        onSCPlay(frameid,SC.Widget.Events.PLAY_PROGRESS);
       });
     });
    });
   }());

这种方法是为处理这两种 API 的多个播放器而设置的,如果您想支持其他可嵌入的媒体小部件(如果它们在开始播放时公开事件并且能够以编程方式暂停播放器),则应该可以很好地扩展).

This approach is set up to handle multiple players of both APIs, and should be decently extensible if you want to support other embeddable media widgets (provided they expose an event when they start to play and they have the ability to programmatically pause players).

相关文章