4

我很抱歉,因为我对我的问题感到非常困惑。我真的陷入困境,因为这导致我的生产站点出现问题。

我的网站上有一个 javascript 播放器,它可以播放可以托管在 youtube、soundcloud 或 vimeo 上的歌曲列表。昨天我注意到这个错误,通常在您尝试通过播放器按钮“跳过”加载新歌曲时出现。这个错误在最后一两天才开始。我在 youtube api 发行说明中没有看到任何新内容,并且使用 Chrome、Firefox 和 Safari 时会发生此错误,因此很可能与浏览器的更改无关。我使用的东西已经改变了,因为我在 18 天内没有推送新代码。

一个示例播放列表在这里: http: //www.muusical.com/playlists/programming-music

我想我已经隔离了重现错误的方法,以下是步骤:

  1. 播放 youtube 托管的歌曲。
  2. 跳到列表中的任何其他歌曲(无论是按跳过按钮还是直接按歌曲行项目上的播放按钮)。

*请注意,如果播放列表中的第一首歌曲是 youtube 歌曲,即使不播放最初加载的 youtube 歌曲,直接跳到另一首歌曲也会产生错误。

从本质上讲,一旦您加载和/或播放了一首 youtube 歌曲并尝试跳到另一首歌曲,该错误似乎就会发生。

如果您发现此行为的例外情况,请告诉我。

我在控制台中看到了这个错误:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.muusical.com') does not match the recipient window's origin ('http://www.muusical.com').

我使用 youtube javascript api 加载播放器:

new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
        'onReady': @initPlayerControls,
        'onStateChange': @onPlayerStateChange
      }
    })

这会产生这个 iframe:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src="https://www.youtube.com/embed/gJ6APKIjFQY?autoplay=1&amp;enablejsapi=1&amp;origin=http%3A%2F%2Fwww.muusical.com"></iframe>

从上面的 youtube 歌曲中点击跳过后,这是我在 iframe 中看到的加载内容:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src=""></iframe>

我支持 youtube、soundcloud 和 vimeo 歌曲。似乎一旦加载了 youtube 歌曲,“来源”就会从 http 更改为 https。我认为没有必要包含其他主机的嵌入方法,因为即使整个播放列表只是 youtube 并且它不会出现在仅包含来自 soundcloud 和 vimeo 的歌曲的播放列表中,也会发生此错误。

此外,这就是我加载 youtube javascript 的方式:

// Load the IFrame Player API code asynchronously.
  var tag = document.createElement('script');
  tag.src = "https://www.youtube.com/player_api";
  var firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

如果您需要我澄清任何事情,请告诉我,并提前感谢您查看。

4

4 回答 4

3

我已经阅读了一些关于此的内容,这里和那里的一些 SO 帖子以及此链接:https ://code.google.com/p/gdata-issues/issues/detail?id=5788

我正要对你的问题添加评论,说我对此感到疯狂......但是当我开始描述我的设置时,我找到了一种避免这个问题的方法^^。

我从一个空div元素开始,然后使用 Youtube Iframe API 将其转换为iframe具有所有必要选项的元素。

我有多个像这样的 div,并且通常使用相同的 JS 变量来存储所有这些玩家,但一次一个(一个替换另一个,依此类推...... - 它可能会更好,我知道)。

为了解决这个问题,我的想法是在从另一个元素构建新玩家之前先摧毁玩家。youtubePlayer.destroy();我的 Chrome 控制台中不再出现 JS 错误 :)。

希望它有所帮助,我能读到的关于 http 和 https 的所有文献都不适用于我的案例,因为我没有自己设置 iframe URL,而且我的网站恰好不是https ...

我确实在我的 HTML 中恢复了异步调用而不是静态script标记,但我认为这没有必要。

编辑:这个错误消息实际上是相当误导的,它只是模糊地意味着:你没有以正确的方式使用 youtube API :)

于 2015-01-12T21:29:50.663 回答
3

@sodawillow 的回答部分正确,但我想提供解决方案的详细信息以及导致我的代码停止调用该.destroy()方法以删除 youtube 播放器的原因。

我的网站有一个播放器,可以从各种网站交换歌曲,其中一个是 Youtube。根据播放器的类型,可以有不同的方法来移除播放器。我的代码检查是否存在 youtube 播放器,如果通过检查,则它使用.destroy()只有 youtube 播放器具有的方法。问题在于 YouTube 更改了播放器对象上一些静态变量的名称。例如,如果我通过以下方式创建了一个播放器:

var player = new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
      }
    })

然后会有一个player.L保存字符串的变量"player"。因此,为了检查当前播放器是否是 YouTube 播放器并将其删除,我这样做了:

if (player.L == "player") {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

最近某个时候 Youtube 将字符串的位置更改"player"为现在驻留在player.M. 我可以将上面的代码更改为检查player.M而不是,player.L这会起作用,但是为了在将来避免这个问题,我已经实现了:

if (player.destroy) {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

只要 Youtube 没有在.destroy()未宣布的情况下删除该方法,就不会导致任何问题。

所以总而言之,这个问题正如@sodawillow 所猜测的那样,我没有使用.destroy()删除 Youtube 播放器的方法。原因是 Youtube 对他们的 api 进行了一些未经宣布的更改,改变了一些静态变量的位置。

于 2015-01-14T01:17:41.110 回答
2

此错误属于 Google Youtube API。

在“ https://www.youtube.com/iframe_api ”内:

if (!window['YT']) {
    var YT = {loading: 0, loaded: 0};
}
if (!window['YTConfig']) {
    var YTConfig = {'host': 'http://www.youtube.com'};
}

他们使用 http 而不是 https。

我们需要覆盖 'host' 选项和 'widget_referrer' 与 'origin' 相同。

player = new YT.Player('player', {
          host: 'https://www.youtube.com',
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE'
...
          origin: "https://www.enziin.com",
          widget_referrer: "https://www.enziin.com"
}

祝你好运。

于 2017-10-05T10:03:54.007 回答
0

我的解决方案是将所有 Youtube 播放器逻辑写入一个单独的页面(尽可能为空白),并在IFRAME标签中引用该页面。

<iframe src="/youtube_frame/?data=SOME_DATA -%>" height="400px" width="100%" frameborder="0" border="0" scrolling="no"></iframe>

然后,您youtube_frame.html将是这样的:

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

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

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        // event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        console.log("OnplayerStateChange");
        if (event.data == YT.PlayerState.PLAYING && !done) {
          console.log("OnplayerStateChange - If statement");
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

(作为旁注:我的上下文是 Prototype.js 会干扰事件“OnStateChange”,我们无法删除此依赖项。使用 jsfiddle 对重现该问题没有用处,因为它几乎没有依赖项。我的应用程序是内置 Rails,并使用此插件显示视频播放列表:https ://github.com/Giorgio003/Youtube-TV/ )

于 2016-08-18T00:38:39.497 回答