API YouTube iframe: comment contrôler un lecteur iframe qui est déjà en HTML?

je veux pouvoir contrôler les lecteurs YouTube basés iframe. Ces lecteurs seront déjà dans le HTML, mais je veux les contrôler via L'API JavaScript.

j'ai lu la documentation pour L'API iframe qui explique comment ajouter une nouvelle vidéo à la page avec L'API, puis la contrôler avec les fonctions du lecteur YouTube:

var player;
function onYouTubePlayerAPIReady() {
    player = new YT.Player('container', {
        height: '390',
        width: '640',
        videoId: 'u1zgFlCw8Aw',
        events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
        }
    });
}

ce code crée un nouvel objet player et l'assigne à "player", puis l'insère dans la #container div. Ensuite je peux opérer sur 'player' et appeler playVideo() , pauseVideo() , etc. sur elle.

mais je veux pouvoir opérer sur des lecteurs iframe qui sont déjà sur la page.

je pourrais le faire très facilement avec l'ancienne méthode embed, avec quelque chose comme:

player = getElementById('whateverID');
player.playVideo();

mais cela ne fonctionne pas avec les nouvelles iframes. Comment attribuer un objet iframe déjà sur la page et ensuite utiliser les fonctions API dessus?

137
demandé sur Peter Mortensen 2011-09-16 14:49:38

4 réponses

Violon Liens: code Source - Aperçu - Petite version

Maj: cette petite fonction n'exécute le code que dans une seule direction. Si vous voulez un soutien complet( par exemple les écouteurs d'événement / getters), avoir un regard à écouter pour L'événement Youtube dans jQuery

suite à une analyse approfondie du code, j'ai créé une fonction: function callPlayer demande un appel de fonction sur toute vidéo encadrée YouTube. Voir le référence Api YouTube pour obtenir une liste complète des appels de fonction possibles. Lisez les commentaires au code source pour une explication.

le 17 mai 2012, la taille du code a été doublé afin de prendre soin de l'état prêt. Si vous avez besoin d'une fonction compacte qui ne traite pas avec le joueur état prêt, voir http://jsfiddle.net/8R5y6 / .

/**
 * @author       Rob W <gwnRob@gmail.com>
 * @website      https://stackoverflow.com/a/7513356/938089
 * @version      20131010
 * @description  Executes function on a framed YouTube video (see website link)
 *               For a full list of possible functions, see:
 *               https://developers.google.com/youtube/js_api_reference
 * @param String frame_id The id of (the div containing) the frame
 * @param String func     Desired function to call, eg. "playVideo"
 *        (Function)      Function to call when the player is ready.
 * @param Array  args     (optional) List of arguments to pass to function func*/
function callPlayer(frame_id, func, args) {
    if (window.jQuery && frame_id instanceof jQuery) frame_id = frame_id.get(0).id;
    var iframe = document.getElementById(frame_id);
    if (iframe && iframe.tagName.toUpperCase() != 'IFRAME') {
        iframe = iframe.getElementsByTagName('iframe')[0];
    }

    // When the player is not ready yet, add the event to a queue
    // Each frame_id is associated with an own queue.
    // Each queue has three possible states:
    //  undefined = uninitialised / array = queue / 0 = ready
    if (!callPlayer.queue) callPlayer.queue = {};
    var queue = callPlayer.queue[frame_id],
        domReady = document.readyState == 'complete';

    if (domReady && !iframe) {
        // DOM is ready and iframe does not exist. Log a message
        window.console && console.log('callPlayer: Frame not found; id=' + frame_id);
        if (queue) clearInterval(queue.poller);
    } else if (func === 'listening') {
        // Sending the "listener" message to the frame, to request status updates
        if (iframe && iframe.contentWindow) {
            func = '{"event":"listening","id":' + JSON.stringify(''+frame_id) + '}';
            iframe.contentWindow.postMessage(func, '*');
        }
    } else if (!domReady ||
               iframe && (!iframe.contentWindow || queue && !queue.ready) ||
               (!queue || !queue.ready) && typeof func === 'function') {
        if (!queue) queue = callPlayer.queue[frame_id] = [];
        queue.push([func, args]);
        if (!('poller' in queue)) {
            // keep polling until the document and frame is ready
            queue.poller = setInterval(function() {
                callPlayer(frame_id, 'listening');
            }, 250);
            // Add a global "message" event listener, to catch status updates:
            messageEvent(1, function runOnceReady(e) {
                if (!iframe) {
                    iframe = document.getElementById(frame_id);
                    if (!iframe) return;
                    if (iframe.tagName.toUpperCase() != 'IFRAME') {
                        iframe = iframe.getElementsByTagName('iframe')[0];
                        if (!iframe) return;
                    }
                }
                if (e.source === iframe.contentWindow) {
                    // Assume that the player is ready if we receive a
                    // message from the iframe
                    clearInterval(queue.poller);
                    queue.ready = true;
                    messageEvent(0, runOnceReady);
                    // .. and release the queue:
                    while (tmp = queue.shift()) {
                        callPlayer(frame_id, tmp[0], tmp[1]);
                    }
                }
            }, false);
        }
    } else if (iframe && iframe.contentWindow) {
        // When a function is supplied, just call it (like "onYouTubePlayerReady")
        if (func.call) return func();
        // Frame exists, send message
        iframe.contentWindow.postMessage(JSON.stringify({
            "event": "command",
            "func": func,
            "args": args || [],
            "id": frame_id
        }), "*");
    }
    /* IE8 does not support addEventListener... */
    function messageEvent(add, listener) {
        var w3 = add ? window.addEventListener : window.removeEventListener;
        w3 ?
            w3('message', listener, !1)
        :
            (add ? window.attachEvent : window.detachEvent)('onmessage', listener);
    }
}

Utilisation:

callPlayer("whateverID", function() {
    // This function runs once the player is ready ("onYouTubePlayerReady")
    callPlayer("whateverID", "playVideo");
});
// When the player is not ready yet, the function will be queued.
// When the iframe cannot be found, a message is logged in the console.
callPlayer("whateverID", "playVideo");

questions possibles (&réponses):

Q : ça ne marche pas!

Un : "Ne fonctionne pas" n'est pas une description claire. Ne vous obtenez des messages d'erreur? Veuillez indiquer le code correspondant.

Q : J'ai intégré une vidéo YouTube en utilisant <iframe src="http://www.youtube.com/embed/As2rZGPGKDY" /> mais la fonction n'exécute aucune fonction!

Un : Vous devez ajouter ?enablejsapi=1 à la fin de votre URL: /embed/vid_id?enablejsapi=1 .

Q : j'obtiens le message d'erreur "une chaîne invalide ou illégale a été spécifiée". Pourquoi?

A : L'API ne fonctionne pas correctement sur un hôte local ( file:// ). Votre hôte (test) de la page en ligne, ou l'utilisation JSFiddle . Exemples: Voir les liens en haut de cette réponse.

Q : comment le savez-vous?

A : j'ai passé un certain temps à interpréter manuellement la source de L'API. J'ai conclu que je devais utiliser la méthode postMessage . Pour savoir quels arguments passer, j'ai créé une extension Chrome qui intercepte les messages. Le le code source de l'extension peut être téléchargé ici .

Q : quels navigateurs sont pris en charge?

A : chaque navigateur qui supporte JSON et postMessage .

  • IE 8+
  • Firefox 3.6+ (en fait 3.5, mais document.readyState a été mis en œuvre en 3.6)
  • Opera 10.50+
  • Safari 4+
  • Chrome 3+

Liées touche de prise / mise en œuvre: Fondu dans un encadré vidéo à l'aide de jQuery

Prise en charge complète de L'API: "Listening for Youtube Event in jQuery

API officielle: https://developers.google.com/youtube/iframe_api_reference

Historique des révisions

  • 17 mai 2012

    Mis en œuvre onYouTubePlayerReady : callPlayer('frame_id', function() { ... }) .

    Les fonctions sont automatiquement mises en file d'attente lorsque le lecteur n'est pas encore prêt.
  • 24 juillet 2012

    Mis à jour et testé avec succès dans les navigateurs pris en charge (look ahead).
  • 10 octobre 2013 Quand une fonction est passée comme argument, callPlayer forces un contrôle de l'état de préparation. Cela est nécessaire, parce que lorsque callPlayer est appelé juste après l'insertion de l'iframe pendant que le document est prêt, il ne peut pas savoir avec certitude que l'iframe est entièrement prêt. Dans Internet Explorer et Firefox, ce scénario a conduit à une invocation trop précoce de postMessage , qui a été ignorée.
  • 12 décembre 2013, recommandé d'ajouter &origin=* dans l'URL.
  • 2 mars 2014, rétractée recommandation de supprimer &origin=* à L'URL.
290
répondu Rob W 2017-05-23 12:03:07

semble comme YouTube a mis à jour leur API JS donc c'est disponible par défaut! Vous pouvez utiliser un ID YouTube iframe existant...

<iframe id="player" src="http://www.youtube.com/embed/M7lc1UVf-VE?enablejsapi=1&origin=http://example.com" frameborder="0"></iframe>

... dans votre JS...

var player;
function onYouTubeIframeAPIReady() {
  player = new YT.Player('player', {
    events: {
      'onStateChange': onPlayerStateChange
    }
  });
}

function onPlayerStateChange() {
  //...
}

...et le constructeur utilise votre iframe au lieu de la remplacer par une nouvelle. Cela signifie également que vous n'avez pas à spécifier le videoId du constructeur.

voir Chargement d'un lecteur vidéo

30
répondu CletusW 2013-07-29 21:38:59

vous pouvez le faire avec beaucoup moins de code:

function callPlayer(func, args) {
    var i = 0,
        iframes = document.getElementsByTagName('iframe'),
        src = '';
    for (i = 0; i < iframes.length; i += 1) {
        src = iframes[i].getAttribute('src');
        if (src && src.indexOf('youtube.com/embed') !== -1) {
            iframes[i].contentWindow.postMessage(JSON.stringify({
                'event': 'command',
                'func': func,
                'args': args || []
            }), '*');
        }
    }
}

exemple pratique: http://jsfiddle.net/kmturley/g6P5H/296 /

16
répondu Kim T 2015-06-24 00:39:09

ma propre version du code de Kim t ci-dessus qui se combine avec certains jQuery et permet de cibler des iframes spécifiques.

$(function() {
    callPlayer($('#iframe')[0], 'unMute');
});

function callPlayer(iframe, func, args) {
    if ( iframe.src.indexOf('youtube.com/embed') !== -1) {
        iframe.contentWindow.postMessage( JSON.stringify({
            'event': 'command',
            'func': func,
            'args': args || []
        } ), '*');
    }
}
4
répondu adamj 2015-07-24 13:00:27