webentwicklung-frage-antwort-db.com.de

laden mehrerer Videoplayer mit youtube api

Ich muss mehr als ein Video mit der Youtube-API laden. Ich benutze es zum ersten Mal, daher bin ich mir nicht sicher, was ich falsch mache, aber das versuche ich:

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

Da onYouTubeIframeAPIReady nur aufgerufen werden soll, wenn der folgende Ansatz verwendet werden kann:

  • video-Player-Informationen (ControlId,width,height,VideoId) in Array initialisieren und speichern

  • rufen Sie die Funktion onYouTubeIframeAPIReady auf, um alle Video-Player (.____.) zu erstellen 

Beispiel

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
          });
      }
23

Der erste Parameter des neuen YT.Player muss die ID des HTML-Elements sein (z. B. ein DIV), das durch einen iframe für das Video ersetzt werden soll lädt beide in dasselbe Element.

<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>

Die Parameter der Funktionen sind in der Youtube API-Dokumentation beschrieben: 
https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player (BEARBEITEN: Zum rechten Link geändert)

20
Egari

Ich hatte ein umfangreicheres Problem, das auf dasselbe Problem zurückzuführen war. Ich musste eine JS-Klasse schreiben, um ein oder mehrere (die Anzahl kann von 1 bis unendlich variieren) Video-Einbettungen zu verwalten. Das Backend-System ist ExpressionEngine (aber das ist hier irrelevant). Das Hauptziel bestand darin, ein Framework für Analysen einzurichten, das individuelle Daten auf unsere Adobe Analytics-Plattform überträgt. Hier wird nur der Teil gezeigt, der das Spiel zählt, es kann von hier aus viel erweitert werden.

Mit dem CMS können Redakteure auf der Seite Module erstellen, die ein Video enthalten. Ein Video pro Modul. Jedes Modul ist im Wesentlichen ein Abschnitt von HTML, der über Bootstrap 3 angeordnet wird (für diese Antwort nicht relevant). 

Der entsprechende HTML-Code sieht folgendermaßen aus:

<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>

Der Teil, der "{innov_mod_ytplayer: id}" sagt, ist die YouTube-Video-ID aus unserem CMS. Dies ermöglicht eine eindeutige ID für jedes eingebettete Element. Das ist später wichtig.

Darunter rendere ich dann aus:

            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){}
            })();

Hier finden Sie auch einige TemplateEngine-Tags von ExpressionEngine. Hierbei handelt es sich lediglich um die Video-ID und den Videotitel von YouTube. Um dies zu replizieren, müssen Sie diese natürlich ändern.

Dadurch kann ich den einzelnen globalen Rückruf mit neuem Code für jedes neu eingebettete Video dynamisch aktualisieren. Am Ende enthält dieser Rückruf Aufrufe an die eigenen Instanzen meiner Klasse. Sie benötigen diese try/catch-Blöcke, da dies einen falsch positiven Fehler für alle "anderen" Einbettungen auslöst, mit Ausnahme derjenigen, die gerade "gerade" ausgeführt werden. Denken Sie daran, dass dieses Skript einmal für jede Einbettung auf der Seite ausgeführt wird. Die Fehler werden erwartet und verursachen eigentlich kein Problem, sodass Try/Catch sie unterdrückt.

Mit dem CMS-Vorlagen-Tag erstelle ich jede Instanz basierend auf der YouTube-Video-ID. Ich würde auf ein Problem stoßen, wenn jemand dasselbe Videomodul mehr als einmal hinzufügt. Dies ist jedoch ein leicht zu handhabendes Geschäftsproblem, da dies nicht der Fall sein sollte. Dadurch kann ich für jedes Video immer wieder eindeutige Instanzen meiner Klasse instanziieren. 

Der kritische Teil dieses Skripts basiert auf dieser äußerst hilfreichen SO answer: Hinzufügen von Code zu einer Javascript-Funktion programmgesteuert

Hier ist die eigentliche Klasse. Meistens kommentiert ... Wir verwenden jQuery, daher wird hier in der $ .extend () -Methode eine wichtige Verwendung davon gesehen. Ich benutze das als Bequemlichkeit in der Klassenkonstruktormethode, aber Sie könnten das auch mit Vanilla JS tun ( JavaScript-Äquivalent der jQuery-Erweiterungsmethode ). Ich finde, dass jQuery einfacher zu lesen ist benutze es.

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');
            }
        }
    }
}

Einige andere Anmerkungen:

Das Beibehalten des Gültigkeitsbereichs in der Klasseninstanz ist einfach, wenn das Hauptproblem des globalen Rückrufs behoben ist. Sie müssen nur .bind () hinzufügen. Zum Beispiel:

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

Sie könnten auch sehen:

var _this = this;

Dies ist so, dass der Bereich "this" für die Instanz nicht versehentlich verloren geht. Vielleicht nicht notwendig, aber es ist eine Konvention, die ich im Laufe der Jahre übernommen habe. 

Wie auch immer, ich arbeite jetzt schon seit einer Woche daran und dachte mir, ich würde es mit der SO-Community teilen, da aus meiner Suche nach Antworten hervorgeht, dass viele andere nach Lösungen dafür gesucht haben auch.

2
Carnix

Ich brauchte dasselbe in React. Wenn Sie auf die Antwort von Vadim eingehen, können Sie Folgendes tun und einem Objekt hinzufügen. Erstellen Sie dann den Player, wenn Sie nicht wissen, wie das Array von Playern zuvor aussieht.

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

Das HTML

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

Die JS für 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;

})();

Erstellen Sie dann Videos wie diese

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