web-dev-qa-db-ja.com

YouTube APIで複数のビデオプレーヤーをロードする

YouTubeのAPIで複数の動画を読み込む必要があります。これは初めて使用するため、何が問題なのかわかりませんが、これは私が試していることです。

  var player;
  var player2;
  function onYouTubePlayerAPIReady() {
    player = new YT.Player('player', {
      videoId: 'hdy78ehsjdi'
    });
    player2 = new YT.Player('player', {
      videoId: '81hdjskilct'
    });
  }
17
Hello World

onYouTubeIframeAPIReady関数は、次のアプローチを使用できる場合にのみ呼び出されることになっているため、

  • 動画プレーヤー情報を初期化して保存します(ControlId,width,height,VideoId)配列

  • onYouTubeIframeAPIReady関数を呼び出して、すべてのビデオプレーヤーを作成します

var playerInfoList = [{id:'player',height:'390',width:'640',videoId:'M7lc1UVf-VE'},{id:'player1',height:'390',width:'640',videoId:'M7lc1UVf-VE'}];

      function onYouTubeIframeAPIReady() {
        if(typeof playerInfoList === 'undefined')
           return; 

        for(var i = 0; i < playerInfoList.length;i++) {
          var curplayer = createPlayer(playerInfoList[i]);
        }   
      }
      function createPlayer(playerInfo) {
          return new YT.Player(playerInfo.id, {
             height: playerInfo.height,
             width: playerInfo.width,
             videoId: playerInfo.videoId
          });
      }
28

新しいYT.Playerの最初のパラメータは、動画のiframeで置き換えるHTML要素(DIVなど)のIDである必要があります。これらのオブジェクトの両方に「player」を使用すると、両方を同じ要素にロードします。

<div id="ytplayer1"></div>
<div id="ytplayer2"></div>

<script>
  var player;
  var player2;
  function onYouTubePlayerAPIReady() {
    player = new YT.Player('ytplayer1', {
      height: '390',
      width: '640',
      videoId: 'hdy78ehsjdi'
    });
    player2 = new YT.Player('ytplayer2', {
      height: '390',
      width: '640',
      videoId: '81hdjskilct'
    });
  }
</script>

関数のパラメーターについては、Youtube APIドキュメントで説明されています。
https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player (編集:正しいリンクに変更)

22
Egari

私はこれと同じ問題に要約されるより広範な問題を抱えていました。私が持っていた要件は、1つまたは複数(数は1から無限まで変化する可能性があります)のビデオ埋め込みを管理するJSクラスを作成することでした。バックエンドシステムはExpressionEngineです(ただし、ここでは関係ありません)。主な目標は、個々のデータをAdobe Analyticsプラットフォームにプッシュする分析のフレームワークをセットアップすることでした。ここに示されているのは、再生回数を提供する部分にすぎません。ここから大幅に拡張できます。

CMSを使用すると、編集者はページにビデオを表示するモジュールを作成できます。モジュールごとに1つのビデオ。各モジュールは基本的にBootstrap 3を介して配置されたHTMLのセクションです(この回答には関係ありません)。

関連するHTMLは次のようになります。

<div id="js_youTubeContainer_{innov_mod_ytplayer:id}" class="embed-responsive embed-responsive-16by9">
  <div id="js_youTubeFrame_{innov_mod_ytplayer:id}" class="embed-responsive-item"></div>
</div>

「{innov_mod_ytplayer:id}」という部分は、CMSからのYouTube動画IDです。これにより、埋め込みアイテムごとに一意のIDを使用できます。これは後で重要です。

この下に、次にレンダリングします。

            var innovYouTube_{innov_mod_ytplayer:id} = new Ariba.Innovations.YouTube.Class({
                'innovYouTubeVideoId': '{innov_mod_ytplayer:id}',
                'innovYouTubeVideoTitle': '{innov_mod_ytplayer:title}',
                'innovYouTubeDivId' : 'js_youTubeFrame_{innov_mod_ytplayer:id}'
            });
            innovYouTube_{innov_mod_ytplayer:id}.Init(); // And... Go!

            var onYouTubeIframeAPIReady = (function() {
                try{ //wrap this in try/catch because it actually throws errors when it runs subsequent times - this is expected as it's related to YouTube "rerunning" the function on other videos.
                    innovYouTube_{innov_mod_ytplayer:id}.config.functionCache = onYouTubeIframeAPIReady; //cache the existing global function
                    return function() {
                        try{
                            innovYouTube_{innov_mod_ytplayer:id}.onYouTubeIframeAPIReady(); //execute this instance's function
                            var newOnYouTubeIframeAPIReady = innovYouTube_{innov_mod_ytplayer:id}.config.functionCache.apply(this, arguments); //add instances to global function
                            return newOnYouTubeIframeAPIReady; //update global function
                        }catch(err){}
                    };
                }catch(err){}
            })();

ここにもいくつかのExpressionEngineテンプレートタグが表示されます。これらは、YouTubeからのビデオIDとビデオタイトルです。これを複製するには、もちろんそれらを変更する必要があります。

これにより、新しく埋め込まれた各ビデオの新しいコードで単一のグローバルコールバックを動的に更新できます。最後に、このコールバックには、自分のクラスの独自のインスタンスへの呼び出しが含まれます。これらのtry/catchブロックが必要なのは、実際に「今」実行しているものを除くすべての「その他」の埋め込みに対してfalse-positiveエラーがスローされるためです。このスクリプトは、ページの埋め込みごとに1回実行されることに注意してください。エラーが予想され、実際には問題が発生しないため、try/catchはそれらを抑制します。

CMSテンプレートタグを使用して、YouTube動画IDに基づいて各インスタンスを作成します。誰かが同じビデオモジュールを2回以上追加すると問題が発生しますが、これは発生するはずがないため、簡単に処理できるビジネス上の問題です。これにより、ビデオごとにクラスの一意のインスタンスを何度もインスタンス化できます。

そのスクリプトの重要な部分は、この非常に役立つSO答え: プログラムでJavaScript関数にコードを追加する)に基づいています

これが実際のクラスです。ほとんどコメントされています...私たちはjQueryを使用しているので、ここで$ .extend()メソッドでそれの1つの重要な使用法がわかります。私はこれをクラスコンストラクターメソッドの便宜として使用していますが、Vanilla JSでもそれを行うことができます( jQueryの拡張メソッドと同等のJavaScript )jQueryは読みやすく、また、私、使っています。

if (typeof Ariba === "undefined") { var Ariba = {}; }
if (typeof Ariba.Innovations === "undefined") { Ariba.Innovations = {}; }
if (typeof Ariba.Innovations.YouTube === "undefined") { Ariba.Innovations.YouTube = {}; }

if (typeof Ariba.Innovations.YouTube.Class === "undefined") {//this script may be embedded more than once - do this to avoid re-processing it on subsequent loads
    Ariba.Innovations.YouTube.Class = function (config) {
        this.static = {
            'ytScriptId': 'js_youtubeFrameAPI',
            'ytScriptUrl': 'https://www.youtube.com/iframe_api'
        };//static configuration.  Will overwrite any other settings with the same name
        this.config = {//optional configuration variables. Will be overridden by instance or static settings with the same name.
            'adobeAnalyticsFired': false
        };
        this.config = $.extend(true, this.config, config);//inserts (destructively!) the instance settings.
        this.config = $.extend(true, this.config, this.static);//inserts (destructively!) the static settings.
        this.config.this = this;
    };

    Ariba.Innovations.YouTube.Class.prototype.Init = function () {
        //Note: have to allow it to write it over an over because calling the API script is what makes YouTube call onYouTubeIframeAPIReady.
        //if (document.getElementById('js_youtubeFrameAPI') === null) { // don't add the script again if it already exists!
        this.config.apiScript = document.createElement('script');
        this.config.apiScript.src = 'https://www.youtube.com/iframe_api';
        this.config.apiScript.id = 'js_youtubeFrameAPI' + this.config.innovYouTubeVideoId;
        this.config.firstScriptTag = document.getElementsByTagName('script')[0];
        this.config.firstScriptTag.parentNode.insertBefore(this.config.apiScript, this.config.firstScriptTag);
        //}
        //else { console.log("iframe script already embedded", this.config.innovYouTubeVideoId); }
    }

    Ariba.Innovations.YouTube.Class.prototype.onYouTubeIframeAPIReady = function (event) {
        //console.log("onYouTubeIframeAPIReady", this.config.innovYouTubeVideoId, arguments);
        var _this = this;
        //console.log(this);
        this.config.ytPlayer = new YT.Player(this.config.innovYouTubeDivId, {
            videoId: this.config.innovYouTubeVideoId,
            events: {
                'onReady': _this.onPlayerReady.bind(_this),
                'onStateChange': _this.onPlayerStateChange.bind(_this)
            }
        });
    }

    Ariba.Innovations.YouTube.Class.prototype.onPlayerReady = function (event) {
        //console.log("onPlayerReady", this.config.innovYouTubeVideoId, event);
    }

    Ariba.Innovations.YouTube.Class.prototype.onPlayerStateChange = function (event) {
        //console.log("onPlayerStateChange", this.config.innovYouTubeVideoId, event, this);
        if (event.data === YT.PlayerState.PLAYING && !this.config.adobeAnalyticsFired) {
            //console.log("YouTube Video is PLAYING!!", this.config.innovYouTubeVideoId);
            this.config.adobeAnalyticsFired = true;
            if (typeof _satellite !== "undefined") {
                window._satellite.data.customVars.adhoc_tracker_val = "Innovations Video: " + this.config.innovYouTubeVideoTitle + " (" + this.config.innovYouTubeVideoId + ")";
                _satellite.track('adhoctrack');
            }
        }
    }
}

その他の注意事項:

メインのグローバルコールバックの問題を解決すれば、クラスインスタンスのスコープを維持するのは簡単です。 .bind()を追加するだけです。例えば:

'onReady': _this.onPlayerReady.bind(_this)

あなたも見るかもしれません:

var _this = this;

これは、インスタンスの「this」スコープが誤って失われないようにするためです。必要ではないかもしれませんが、それは私が長年にわたって採用してきた慣習です。

とにかく、私は1週間これに取り組んでいて、SOコミュニティと共有するだろうと考えました。これに対する解決策も。

2
Carnix

Reactでもこれと同じものが必要でした。ヴァディムの答えを拡張すると、次のようなことができ、オブジェクトに追加して、プレーヤーの配列が以前のように見えない場合はプレーヤーを作成できます。

const YoutubeAPILoader = {
  _queue: [],
  _isLoaded: false,

  load: function (component) {
    // if the API is loaded just create the player
    if (this._isLoaded) {
      component._createPlayer()
    } else {
      this._queue.Push(component)

      // load the Youtube API if this was the first component added
      if (this._queue.length === 1) {
        this._loadAPI()
      }
    }
  },

  _loadAPI: function () {
    // load the api however you like
    loadAPI('//youtube.com/player_api')

    window.onYouTubeIframeAPIReady = () => {
      this._isLoaded = true
      for (let i = this._queue.length; i--;) {
        this._queue[i]._createPlayer()
      }
      this._queue = []
    }
  }
}
1
souporserious

HTML

<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>
<div data-id="youtubevideoidhere" class="video"></div>

JS for Videos

// CREATE VIDEOS "CLASS" to handler videos
var Videos = (function() {
    // VARIABLES
    var $   = jQuery,   // The jquery
    players = [],       // players array (to coltrol players individually)
    queue   = [];       // videos queue (once api is ready, transform this into YT player)

    // Constructor
    function Videos() {}

    // METHODS
    // Add elements to queue
    Videos.prototype.add = function($video) {
        queue.Push($video);
    };

    // Load YT API
    Videos.prototype.loadApi = function() {
        // jQuery get script
        $.getScript("//www.youtube.com/iframe_api", function() {
            // once loaded, create the onYouTubeIframeAPIReady function
            window.onYouTubeIframeAPIReady = function() {
                queue.forEach(function($video) {
                    // Create the YT player
                    var player = new YT.Player($video.get(0), {
                        'width': "100%",
                        'height': "100%",
                        'videoId': $video.data("id")
                    });
                    // add to players array
                    players.Push(player);
                });
            };
        });
    };

    return Videos;

})();

そして、このようなビデオを作成します

var videos = new Videos();
$('.video').each( function () {
    videos.add( $(this) );
})
videos.loadApi();
1
Dihgg