토론 » 개발

Access Iframe Content

§
게시: 2019-04-06

Access Iframe Content

I'm trying to access a video inside an iframe, but I am getting the error "Permission denied to access property x on cross-origin object" for the innerDoc video. The iframe is youtube, so I have this as my userscript property:

// @include https://original-website.com/*
// @match *.youtube.com/*

And here is my javascript:

    var video, mode, iframe, innerDoc;

    $('.speed-control button').on('click', (evt) => {

        mode = $(event.target).attr('class').match(/speed-control-(.*)/)[1];        
        iframe = document.getElementById('videoPlayer_Youtube_api');
        innerDoc = (iframe.contentWindow || iframe.contentDocument);
        video = innerDoc.querySelectorAll('video');

        switch(mode){
            case 'slow':
                video.playbackRate  = 0.5;
                break;
            case 'normal':
                video.playbackRate  = 1;
                break;
            case 'fast':
                video.playbackRate  = 2;
                break;
            default:
        }

    });
woxxom관리자
§
게시: 2019-04-06

Modern browsers can't access a cross-domain iframe contents directly. Since your userscript runs both on the main page and inside the iframe you can use cross-window messaging:

const MSG_PREFIX = GM_info.script.name + '\n';

if (window === top) {

  $('.speed-control button').on('click', function () {
    const payload = JSON.stringify({
      action: 'speedControl',
      data: this.className.match(/speed-control-(.*)/)[1],
    });
    const iframe = document.getElementById('videoPlayer_Youtube_api');
    iframe.contentWindow.postMessage(MSG_PREFIX + payload, '*');
  });

} else if (location.hostname.endsWith('youtube.com')) {

  const ACTIONS = {
    speedControl(mode) {
      switch (mode) {
        case 'slow':
          video.playbackRate = 0.5;
          break;
        case 'normal':
          video.playbackRate = 1;
          break;
        case 'fast':
          video.playbackRate = 2;
          break;
        default:
      }
    },
  };

  window.addEventListener('message', e => {
    if (typeof e.data === 'string' && e.data.startsWith(MSG_PREFIX)) {
      try {
        const payload = e.data.slice(MSG_PREFIX.length);
        const {action, data} = JSON.parse(payload);
        if (ACTIONS.hasOwnProperty(action)) {
          ACTIONS[action](data);
        }
      }
      catch (ex) {}
    }
  });

}
§
게시: 2019-04-06

Thank you so much! I just had to define the video variable but other than that, your code works really well. Gonna look into postMessage more to understand it better.

답글 게시

답글을 게시하려면 로그인하세요.

长期地址
遇到问题?请前往 GitHub 提 Issues。