讨论 » 开发

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.

发布留言

登录以发布留言。