programing

YouTube iframe API: HTML에 이미 있는 iframe 플레이어를 제어하려면 어떻게 해야 합니까?

stoneblock 2023. 10. 11. 20:26

YouTube iframe API: HTML에 이미 있는 iframe 플레이어를 제어하려면 어떻게 해야 합니까?

iframe 기반의 유튜브 플레이어를 제어할 수 있기를 원합니다.이 플레이어들은 이미 HTML에 들어가 있겠지만, 자바스크립트 API를 통해 제어하고 싶습니다.

API로 페이지에 새로운 동영상을 추가하고 유튜브 플레이어 기능으로 제어하는 방법을 설명하는 iframe API에 대한 설명서를 읽고 있습니다.

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

하지만 이것은 새로운 iframe에서는 작동하지 않습니다.페이지에 이미 있는 iframe 객체를 할당하고 그 위에 API 기능을 사용하려면 어떻게 해야 합니까?

Fiddle Links : 소스 코드 - 미리보기 - 소형 버전
업데이트:이 작은 함수는 단일 방향으로만 코드를 실행합니다.전체 지원(예: 이벤트 청취자/수신자)을 원한다면 jQuery에서 Listening for Youtube Event확인해 보십시오.

, function callPlayer틀에 박힌 유투브 비디오에 대한 기능 호출을 요청합니다.가능한 기능 호출의 전체 목록을 보려면 YouTube Api 참조를 참조하십시오.소스코드의 코멘트를 읽고 설명을 듣습니다.

2012년 5월 17일, 플레이어의 준비 상태를 관리하기 위해 코드 크기를 두 배로 늘렸습니다.플레이어의 준비 상태를 다루지 않는 컴팩트한 기능이 필요한 경우 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");

가능한 질문(및 답변):

Q: 작동이 안 돼요!
A: "Don't work"는 명확한 설명이 아닙니다.오류 메시지가 있습니까?관련 코드를 보여주시기 바랍니다.

Q:playVideo는 비디오를 재생하지 않습니다.
A: 재생을 하려면 사용자 상호 작용이 필요하고, 사용자의 존재가 있어야 합니다.allow="autoplay"이프레임에https://developers.google.com/web/updates/2017/09/autoplay-policy-changes https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide 참조

Q: 다음을 사용하여 유튜브 동영상을 삽입했습니다.<iframe src="http://www.youtube.com/embed/As2rZGPGKDY" />하지만 그 기능은 어떤 기능도 실행하지 않습니다!
A: 추가하셔야 합니다.?enablejsapi=1: URL과의와)/embed/vid_id?enablejsapi=1.

Q: "잘못되거나 잘못된 문자열이 지정되었습니다"라는 오류 메시지가 나타납니다. 이유는 무엇입니까?
A: 로컬 호스트에서 API가 제대로 작동하지 않습니다(file://(테스트) 페이지를 온라인으로 호스팅하거나, JSFiddle을 사용합니다.예:이 답변의 맨 위에 있는 링크를 참조하십시오.

Q: 어떻게 알았습니까?
A: API의 출처를 수동으로 해석하는 데 시간이 좀 걸렸습니다.저는 그 방법을 사용해야 한다는 결론을 내렸습니다.어떤 인수를 통과해야 할지 알기 위해 메시지를 가로채는 크롬 확장자를 만들었습니다.확장자의 소스코드는 여기서 다운로드 받을 수 있습니다.

Q: 어떤 브라우저가 지원됩니까?
A: JSON과 를 지원하는 모든 브라우저.

  • IE 8+
  • 이지만 Firefox 3.6+(는 3.5 이지만)document.readyState3.6)되었습니다.
  • 오페라 10.50+
  • 사파리 4+
  • 크롬3+

관련 답변/구현:프레임 비디오에서 jQuery를 사용하여 페이드 인
전체 API 지원 : jQuery에서 Youtube 이벤트 듣기
공식 API : https://developers.google.com/youtube/iframe_api_reference

개정이력

  • 2012년5월17일
    tonYouTubePlayerReady:callPlayer('frame_id', function() { ... }).
    플레이어가 아직 준비되지 않았을 때 기능이 자동으로 대기합니다.
  • 2012년7월24일
    지원되는 브라우저에서 업데이트되고 성공적으로 테스트되었습니다(앞을 내다보세요).
  • 2013 10 10 ,callPlayer준비 상태를 강제로 체크합니다..callPlayer문서가 준비되는 동안 iframe을 삽입한 직후에 호출됩니다. iframe이 완전히 준비되었는지 확실히 알 수 없습니다.및 Firefox에서 이 시나리오는 했습니다 Firefox와를 를 초래했습니다.postMessage
  • 2013년 12 12 &origin=*URL에 저장합니다.
  • 3 2 제거 철회, &origin=*URL로 이동합니다.
  • 2019년 4월 9일 페이지가 준비되기 전에 유튜브 로드 시 무한 재귀를 초래한 버그 수정자동 재생에 대한 참고 사항을 추가합니다.

유튜브가 JS API를 업데이트한 것 같아서 기본적으로 사용할 수 있습니다!기존 유투브를 사용할 수 있는 iframe의 아이디는...

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

당신의 JS에...

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

function onPlayerStateChange() {
  //...
}

...시공자는 기존 아이프레임을 새 아이프레임으로 교체하는 대신 사용할 것입니다.videoId를 생성자에게 지정하지 않아도 됩니다.

비디오 플레이어 로드 참조

훨씬 적은 코드로 이 작업을 수행할 수 있습니다.

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/

일부 jQuery와 결합하여 특정 iframe의 타겟팅이 가능한 위의 Kim T 코드의 나만의 버전.

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

롭 W씨의 답변에 감사드립니다.

API를 로드할 필요가 없고 동적으로 로드되는 프레임을 쉽게 제어할 수 있도록 Cordova 애플리케이션 내에서 이를 사용하고 있습니다.

항상 iframe에서 상태(getPlayerState) 및 시간(getCurrentTime)과 같은 정보를 추출할 수 있는 기능을 원했습니다.

Rob W는 postMessage를 사용하여 API가 어떻게 작동하는지 강조하는 것을 도왔지만, 물론 이것은 우리의 웹 페이지에서 iframe으로 한 방향으로만 정보를 보냅니다.게터에 액세스하려면 iframe에서 다시 게시된 메시지를 들어야 합니다.

iframe에 의해 반환된 메시지를 활성화하고 듣기 위해 Rob W의 답변을 조정하는 방법을 찾는 데 시간이 좀 걸렸습니다.저는 기본적으로 유튜브 iframe 내의 소스코드를 검색하여 메시지 송수신을 담당하는 코드를 찾았습니다.

핵심은 '이벤트'를 '듣기'로 바꾸는 것이었습니다. 이를 통해 기본적으로 값을 반환하도록 설계된 모든 방법에 액세스할 수 있게 되었습니다.

아래는 저의 해결책입니다. getter가 요청될 때만 'listening'으로 전환하였으니 조건을 조정하여 추가적인 방법을 포함할 수 있습니다.

window.on message에 console.log(e)를 추가하면 iframe에서 보낸 모든 메시지를 볼 수 있습니다.듣기가 활성화되면 동영상의 현재 시간을 포함한 지속적인 업데이트를 받게 됩니다.getPlayerState와 같은 getter를 호출하면 이러한 지속적인 업데이트가 활성화되지만 상태가 변경된 경우에만 비디오 상태와 관련된 메시지가 전송됩니다.

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

위 예시들에 문제가 있어서 대신 자동 재생 기능이 있는 JS로 클릭 시 iframe을 삽입했는데 잘 작동합니다.저도 비메오나 유튜브를 할 수 있는 기회가 있었기 때문에 그것을 감당할 수 있어야 했습니다.

이 해결책은 놀랍지도 않고, 정리할 수도 있지만, 저에게는 효과가 있었습니다.저도 jQuery를 좋아하지 않지만 프로젝트는 이미 사용하고 있었고 기존 코드를 리팩토링하고 있었습니다. 편하게 치우거나 바닐라 JS로 변환하세요 :)

<!-- HTML -->
<div class="iframe" data-player="viemo" data-src="$PageComponentVideo.VideoId"></div>


<!-- jQuery -->
$(".btnVideoPlay").on("click", function (e) {
        var iframe = $(this).parents(".video-play").siblings(".iframe");
        iframe.show();

        if (iframe.data("player") === "youtube") {
            autoPlayVideo(iframe, iframe.data("src"), "100%", "100%");
        } else {
            autoPlayVideo(iframe, iframe.data("src"), "100%", "100%", true);
        }
    });

    function autoPlayVideo(iframe, vcode, width, height, isVimeo) {
        if (isVimeo) {
            iframe.html(
                '<iframe width="' +
                    width +
                    '" height="' +
                    height +
                    '" src="https://player.vimeo.com/video/' +
                    vcode +
                    '?color=ff9933&portrait=0&autoplay=1" frameborder="0" allowfullscreen wmode="Opaque"></iframe>'
            );
        } else {
            iframe.html(
                '<iframe width="' +
                    width +
                    '" height="' +
                    height +
                    '" src="https://www.youtube.com/embed/' +
                    vcode +
                    '?autoplay=1&loop=1&rel=0&wmode=transparent" frameborder="0" allowfullscreen wmode="Opaque"></iframe>'
            );
        }
    }

요청이 문제가 되지 않고 비디오 표시/숨기기와 같은 것에 대해 이 동작을 원하는 경우 iframe을 제거/추가하거나 iframe을 정리하고 채우는 것이 한 가지 빠른 해결책입니다.src.

const stopPlayerHack = (iframe) => {
    let src = iframe.getAttribute('src');
    iframe.setAttribute('src', '');
    iframe.setAttribute('src', src);
}

if 프레임이 제거되고 재생을 중지한 후 바로 로드됩니다.저의 경우 라이트박스 오픈 시에만 src를 다시 설정하도록 코드를 개선했기 때문에 사용자가 동영상을 볼 것을 요구하는 경우에만 로드가 발생합니다.

언급URL : https://stackoverflow.com/questions/7443578/youtube-iframe-api-how-do-i-control-an-iframe-player-thats-already-in-the-html