YouTube iframe API: मैं एक iframe खिलाड़ी को कैसे नियंत्रित करूं जो HTML में पहले से है?


149

मैं iframe आधारित YouTube खिलाड़ियों को नियंत्रित करने में सक्षम होना चाहता हूं। यह खिलाड़ी पहले से ही HTML में होगा, लेकिन मैं उन्हें जावास्क्रिप्ट एपीआई के माध्यम से नियंत्रित करना चाहता हूं।

मैं iframe API के लिए प्रलेखन पढ़ रहा हूं जो समझाता है कि एपीआई के साथ पृष्ठ पर एक नया वीडियो कैसे जोड़ा जाए, और फिर इसे YouTube प्लेयर फ़ंक्शन के साथ नियंत्रित करें:

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

वह कोड एक नया प्लेयर ऑब्जेक्ट बनाता है और इसे 'प्लेयर' को असाइन करता है, फिर इसे #container div के अंदर इन्सर्ट करता है। तब मैं 'खिलाड़ी' और फोन पर काम कर सकते हैं playVideo(), pauseVideo()इस पर, आदि।

लेकिन मैं iframe खिलाड़ियों को संचालित करने में सक्षम होना चाहता हूं जो पहले से ही पृष्ठ पर हैं।

मैं बहुत आसानी से पुराने एम्बेड विधि के साथ ऐसा कर सकता था, जैसे कुछ:

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

लेकिन यह नए iframes के साथ काम नहीं करता है। मैं पहले से ही पृष्ठ पर एक iframe ऑब्जेक्ट कैसे असाइन कर सकता हूं और फिर उस पर API फ़ंक्शन का उपयोग कर सकता हूं?


मैंने YouTube IFrame API github.com/gajus/playtube के
गजस

जवाबों:


316

फिडल लिंक: सोर्स कोड - प्रीव्यू - लघु संस्करण
अपडेट: यह छोटा फ़ंक्शन केवल एक ही दिशा में कोड को निष्पादित करेगा। यदि आप पूर्ण समर्थन चाहते हैं (उदाहरण के लिए श्रोता / गेटर्स), तो jQuery में Youtube इवेंट के लिए श्रवण पर एक नज़र डालें

एक गहरी कोड विश्लेषण के परिणामस्वरूप, मैंने एक फ़ंक्शन बनाया है: function callPlayerकिसी भी फ़्रेम वाले YouTube वीडियो पर फ़ंक्शन कॉल का अनुरोध करता है। संभावित फ़ंक्शन कॉल की पूरी सूची प्राप्त करने के लिए YouTube Api संदर्भ देखें । स्पष्टीकरण के लिए स्रोत कोड पर टिप्पणियों को पढ़ें।

खिलाड़ी की तैयार स्थिति की देखभाल करने के लिए 17 मई 2012 को कोड आकार दोगुना कर दिया गया था। यदि आपको एक कॉम्पैक्ट फ़ंक्शन की आवश्यकता होती है जो खिलाड़ी की तैयार स्थिति से नहीं निपटती है , तो http://jsfiddle.net/8R5y6/ देखें ।

/**
 * @author       Rob W <gwnRob@gmail.com>
 * @website      https://stackoverflow.com/a/7513356/938089
 * @version      20190409
 * @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 / .ready=true = 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 ((!queue || !queue.ready) && (
               !domReady ||
               iframe && !iframe.contentWindow ||
               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);
    }
}

उपयोग:

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");

संभावित प्रश्न (और उत्तर):

क्यू : यह काम नहीं करता है!
एक : "काम नहीं करता है" एक स्पष्ट विवरण नहीं है। क्या आपको कोई त्रुटि संदेश प्राप्त होता है? कृपया संबंधित कोड दिखाएं।

क्यू : playVideoवीडियो नहीं खेलता है।
A : प्लेबैक को उपयोगकर्ता सहभागिता, और allow="autoplay"iframe की उपस्थिति की आवश्यकता होती है । देखें https://developers.google.com/web/updates/2017/09/autoplay-policy-changes और https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide

प्रश्न : मैंने एक YouTube वीडियो का उपयोग करके एम्बेड किया है, <iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />लेकिन फ़ंक्शन किसी फ़ंक्शन को निष्पादित नहीं करता है!
एक : आप जोड़ने के लिए ?enablejsapi=1अपने URL के अंत में: /embed/vid_id?enablejsapi=1

प्रश्न : मुझे त्रुटि संदेश "एक अवैध या अवैध स्ट्रिंग निर्दिष्ट किया गया था"। क्यों?
A : API किसी स्थानीय होस्ट ( file://) में ठीक से काम नहीं करता है । अपने ऑनलाइन (परीक्षण) पृष्ठ को होस्ट करें, या JSFiddle का उपयोग करें । उदाहरण: इस उत्तर के शीर्ष पर स्थित लिंक देखें।

प्रश्न : आपको यह कैसे पता चला?
: मैंने एपीआई के स्रोत को मैन्युअल रूप से व्याख्या करने के लिए कुछ समय बिताया है। मैंने निष्कर्ष निकाला कि मुझे postMessageविधि का उपयोग करना था । यह जानने के लिए कि किस तर्क को पारित करना है, मैंने एक क्रोम एक्सटेंशन बनाया जो संदेशों को स्वीकार करता है। एक्सटेंशन के लिए स्रोत कोड यहां डाउनलोड किया जा सकता है

प्रश्न : क्या ब्राउज़र समर्थित हैं?
एक : हर ब्राउज़र जो JSON का समर्थन करता है और postMessage

  • IE 8+
  • फ़ायरफ़ॉक्स 3.6+ (वास्तव में 3.5, लेकिन document.readyState3.6 में लागू किया गया था)
  • ओपेरा 10.50+
  • सफारी 4+
  • क्रोम 3+

संबंधित जवाब / कार्यान्वयन: फीका-में फंसाया वीडियो jQuery का उपयोग कर
पूर्ण एपीआई का समर्थन: jQuery में यूट्यूब घटना के लिए सुनकर
सरकारी एपीआई: https://developers.google.com/youtube/iframe_api_reference

संशोधन इतिहास

  • 17 मई 2012
    लागू onYouTubePlayerReady: callPlayer('frame_id', function() { ... })
    जब खिलाड़ी अभी तक तैयार नहीं होता है तो फ़ंक्शंस स्वचालित रूप से पंक्तिबद्ध हो जाते हैं।
  • 24 जुलाई 2012
    अपडेट किया गया और सफलतापूर्वक समर्थित ब्राउज़रों में परीक्षण किया गया (आगे देखें)।
  • 10 अक्टूबर 2013 जब एक समारोह एक तर्क के रूप में पारित किया जाता है, callPlayerतो तत्परता की जांच करता है। इसकी आवश्यकता है, क्योंकि जब callPlayerदस्तावेज़ तैयार होता है, तो iframe के सम्मिलन के बाद इसे सही कहा जाता है, यह सुनिश्चित करने के लिए नहीं जान सकता है कि iframe पूरी तरह से तैयार है। इंटरनेट एक्सप्लोरर और फ़ायरफ़ॉक्स में, इस परिदृश्य के परिणामस्वरूप बहुत जल्दी मंगलाचरण हुआ postMessage, जिसे अनदेखा कर दिया गया।
  • 12 दिसंबर 2013, &origin=*URL में जोड़ने की सिफारिश की गई ।
  • २ मार्च २०१४, &origin=*यूआरएल को हटाने की सिफारिश को वापस ले लिया ।
  • 9 अप्रैल 2019, बग को ठीक करें, जिसके परिणामस्वरूप पृष्ठ तैयार होने से पहले YouTube लोड होने पर अनंत पुनरावृत्ति हो सकती है। ऑटोप्ले के बारे में ध्यान दें।

@RobW मैंने वास्तव में कोशिश की। JSON की तरह लगता है कि त्रुटि आपकी स्क्रिप्ट में नहीं है, लेकिन YouTube के API के एक भाग के रूप में iframe के अंदर है।
फ्रेशेयबेल

@RobW इस अच्छी स्निपेट के लिए धन्यवाद। क्या आपने ईवेंट श्रोता को जोड़ने के लिए YouTube JS API का उपयोग करने के बजाय संदेश ईवेंट का उपयोग करने का कोई तरीका पाया है?
brillout

@ Brightout.com PostMessageविधि YT JS API ( ?enablejsapi=1) पर आधारित है । जेएस एपीआई को सक्षम किए बिना, postMessageविधि कुछ भी नहीं करेगी, इवेंट श्रोताओं के आसान कार्यान्वयन के लिए जुड़ा हुआ जवाब देखें । मैंने भी बनाया है, लेकिन फ्रेम के साथ संवाद करने के लिए प्रकाशित, पठनीय कोड नहीं। मैंने इसे प्रकाशित नहीं करने का निर्णय लिया, क्योंकि इसका प्रभाव डिफ़ॉल्ट YouTube फ़्रेम एपीआई के समान है।
रॉब डब्ल्यू

1
@MatthewBaker जिसे संदेश घटना को सुनने और परिणाम की स्थिति को पार्स करने की आवश्यकता है। यह सरल कॉल की तरह आसान नहीं है playVideo, इसलिए मैं इसके लिए आधिकारिक एपीआई का उपयोग करने की सलाह देता हूं। डेवलपर्स देखें । Googleyoutube/ iframe_api_reference# Events
रॉब डब्ल्यू

1
@ हाँ, मुझे कोई स्पष्ट त्रुटि नहीं दिख रही है। कृपया इस उत्तर में टिप्पणियों में प्रश्न जोड़ने के बजाय एक स्व-निहित चरणों के साथ एक नया प्रश्न पूछें।
रॉब डब्ल्यू

33

लगता है कि YouTube ने अपने JS API को अपडेट कर दिया है इसलिए यह डिफ़ॉल्ट रूप से उपलब्ध है! आप मौजूदा YouTube iframe की ID का उपयोग कर सकते हैं ...

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

... अपने जेएस में ...

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

function onPlayerStateChange() {
  //...
}

... और निर्माणकर्ता आपके मौजूदा iframe को नए के साथ बदलने के बजाय उपयोग करेगा। इसका मतलब यह भी है कि आपको वीडियो को निर्माता को निर्दिष्ट करने की आवश्यकता नहीं है।

वीडियो प्लेयर लोड करना देखें


1
@ आप url में ऑटोप्ले = 1 पैरामीटर को याद कर रहे हैं। आपके उदाहरण url में, यह youtube.com/embed/M7lc1UVf-VE?enablejsapi=1& ऑटोप्ले = 1 और मूल = example.com होगा
alengel

@alengel वह ऑटोप्ले-यूआरएल पैरामीटर का उपयोग नहीं करना चाहता है। इसके बजाय वह js-APIs ऑटोप्ले फ़ंक्शन का उपयोग करके वीडियो शुरू करने का प्रयास करता है। लेकिन किसी कारण से onYouTubeIframeAPIReady () फ़ंक्शन को लागू नहीं किया जाता है।
हम्पाकरीसाज

@ मैं इसे समझ पाया। 1) iframe url से & मूल = example.com निकालें। 2) आपके jsfiddle के "फ्रेमवर्क एंड एक्सटेंशन्स" अनुभाग में दूसरी ड्रॉप डाउन मेनू को "नो रैप इन - <हेड>" 3 पर सेट करें बाहरी संसाधन के रूप में youtube iframe api जोड़ें ( youtube.com/iframe_api ); मैंने आपकी
फ़ाइडल को

किसी भी विचार क्या है eventया स्थिति commandको रोकने के listeningलिए YT iframe को भेजना है ?
19

@CletusW: मुझे यह त्रुटि मिली: अनटाइटेड (वादे में) DOMException: play () अनुरोध को रोकने के लिए एक कॉल द्वारा बाधित किया गया था ()। वादा (async) (अनाम) @ script.js: 20 प्रेषण @ jquery-1.12.4.js: 5226 elemData.handle @ jquery-1.12.4.js: 4878 cast_bender.js: 67 अनलॉक्ड DOMException: 'PresentationRequest' का निर्माण करने में विफल ': एक असुरक्षित दस्तावेज़ की प्रस्तुति [कलाकार: 233637DE; क्षमताओं = वीडियो_आउट% 2Caudio_out & clientId = 153262711713390989 और ऑटो जॉइनपॉलिशी = टैब_and_origin_scoped और defaultActionPolicy = cast_this_tab और लॉन्च = 300-100 = 100 सेकंड के लिए।
लोरनाएमएस

20

आप इसे कम कोड के साथ कर सकते हैं:

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 || []
            }), '*');
        }
    }
}

काम करने का उदाहरण: http://jsfiddle.net/kmturley/g6P5H/296/


मुझे वास्तव में यह पसंद आया, बस इसे एक कोणीय निर्देश के साथ काम करने के लिए अनुकूलित किया गया ताकि सभी लूप की आवश्यकता न हो और गुंजाइश के साथ टॉगल फ़ंक्शन के आधार पर फंक को पास करें (मूल रूप से वीडियो प्रदर्शित होने पर -> ऑटोप्ले; और -> ठहराव चलचित्र)। धन्यवाद!
डीडी।

आपको निर्देश साझा करना चाहिए, उपयोगी हो सकता है!
किम टी

1
यहाँ एक पेन के लिए कोड का एक अनुकूलन है: codepen.io/anon/pen/qERdza मुझे आशा है कि यह मदद करता है! यह भी ESC कुंजी दबाने आप पर वीडियो है जब टॉगल
डीडी।

यह सच होना बहुत अच्छा लगता है! क्या इस विधि का उपयोग करने के लिए कोई ब्राउज़र / सुरक्षा सीमाएँ हैं?
डेन

हाँ IE की कुछ सीमाएँ हैं, विशेष रूप से IE10 जो पोस्टमैसेज के बजाय MessageChannel का समर्थन करता है: caniuse.com/#search=postMessage यह भी ध्यान रखें कि कोई भी सामग्री सुरक्षा नीतियाँ भी इस सुविधा के उपयोग को प्रतिबंधित करेंगी
Kim T

5

ऊपर किम टी के कोड का मेरा अपना संस्करण जो कुछ jQuery के साथ संयोजन करता है और विशिष्ट iframes के लक्ष्यीकरण के लिए अनुमति देता है।

$(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 || []
        } ), '*');
    }
}

कैसे पता करें कि youtube खेल रहा है? youtube iframe से कोई कॉलबैक, तो बाहर की सदस्यता ले सकते हैं?
हैमर

@ Hammer YouTube API ईवेंट इवेंट विशेष रूप से देखें OnStateChange: Developers.google.com/youtube/iframe_api_reference#Events
adamj

@admj, क्या इसकी जाँच कर सकते हैं? कुछ अजीब व्यवहार ... stackoverflow.com/questions/38389802/…
हैमर

0

आपके जवाब के लिए धन्यवाद रॉब डब्ल्यू।

मैं एपीआई को लोड करने से बचने के लिए कॉर्डोवा एप्लिकेशन के भीतर इसका उपयोग कर रहा हूं और ताकि मैं iframes को आसानी से नियंत्रित कर सकूं जो गतिशील रूप से लोड किए गए हैं।

मैं हमेशा से राज्य (getPlayerState) और समय (getCurrentTime) जैसे iframe से जानकारी निकालने में सक्षम होना चाहता था।

रोब डब्ल्यू ने यह बताने में मदद की कि एपीआई पोस्टमैसेज का उपयोग करके कैसे काम करता है, लेकिन निश्चित रूप से यह केवल एक दिशा में जानकारी भेजता है, हमारे वेब पेज से आईफ्रेम में। गेटर्स तक पहुँचने के लिए हमें iframe से हमें वापस पोस्ट किए गए संदेशों को सुनना पड़ता है।

यह पता करने में मुझे कुछ समय लगा कि रोब डब्ल्यू के जवाब को कैसे सक्रिय किया जाए और आईफ्रेम द्वारा लौटाए गए संदेशों को सुनें। मैंने मूल रूप से YouTube iframe के भीतर स्रोत कोड के माध्यम से खोज की, जब तक मुझे संदेश भेजने और प्राप्त करने के लिए ज़िम्मेदार कोड नहीं मिला।

कुंजी 'ईवेंट' को 'सुनने' में बदल रही थी, यह मूल रूप से उन सभी तरीकों तक पहुंच प्रदान करता है जो मूल्यों को वापस करने के लिए डिज़ाइन किए गए थे।

नीचे मेरा समाधान है, कृपया ध्यान दें कि मैंने केवल 'सुनने' के लिए स्विच किया है जब गेटर्स का अनुरोध किया जाता है, तो आप अतिरिक्त तरीकों को शामिल करने के लिए शर्त को ट्विक कर सकते हैं।

आगे ध्यान दें कि आप iframe से भेजे गए सभी संदेशों को window.onmessage में एक कंसोल .log (e) जोड़कर देख सकते हैं। आप देखेंगे कि एक बार सुनने के बाद आप लगातार अपडेट प्राप्त करेंगे जिसमें वीडियो का वर्तमान समय शामिल है। GetPlayerState जैसे कॉलिंग गेटर्स इन निरंतर अद्यतनों को सक्रिय करेंगे, लेकिन केवल तभी वीडियो संदेश भेजेंगे जब राज्य बदल गया हो।

function callPlayer(iframe, func, args) {
    iframe=document.getElementById(iframe);
    var event = "command";
    if(func.indexOf('get')>-1){
        event = "listening";
    }

    if ( iframe&&iframe.src.indexOf('youtube.com/embed') !== -1) {
      iframe.contentWindow.postMessage( JSON.stringify({
          'event': event,
          'func': func,
          'args': args || []
      }), '*');
    }
}
window.onmessage = function(e){
    var data = JSON.parse(e.data);
    data = data.info;
    if(data.currentTime){
        console.log("The current time is "+data.currentTime);
    }
    if(data.playerState){
        console.log("The player state is "+data.playerState);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.